2014年11月3日

Nightly で "@@iterator" が Symbol.iterator に変わりました (更新あり)

Bug 918828 で、これまで文字列の "@@iterator" を使用していた @@iterator プロパティが Symbol.iterator に変更されました。
この変更は Bug 1066322 が FIXED になるまで (つまり Symbol が有効になるまで) Nightly 限定となります。
[11/13 更新] FIXED になりました。Firefox 36 から Symbol 使えるようです。

これまでは、以下のようなコードを書くと動いていましたが、
var a = {
  "@@iterator": function*() {
    yield 1;
    yield 2;
  }
};
[...a];

この変更の後は、以下のように書き換える事で同じ動作をします。

var a = {
  [Symbol.iterator]: function*() {
    yield 1;
    yield 2;
  }
};
[...a];

Computed property を使用しない場合は、以下のようになります。

var a = {
};
a[Symbol.iterator] = function*() {
  yield 1;
  yield 2;
};
[...a];


しばらくは、アドオンや Firefox 本体のコードでは両方をサポートする必要があります。 Bug 918828 のパッチの中では以下のようなコードが多用されていました。

const JS_HAS_SYMBOLS = typeof Symbol === "function";
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";

まとめると以下のようになります。

const JS_HAS_SYMBOLS = typeof Symbol === "function";
const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
var a = {
  [ITERATOR_SYMBOL]: function*() {
    yield 1;
    yield 2;
  }
};
[...a];

2014年11月2日

git でファイルを削除したコミットを調べる

openLocationLastURL.jsm が消えてました の記事で、どのコミットがファイルを削除したかを調べた時の備忘録。

git では削除したファイルのログは通常のコマンドでは見る事ができません。

$ git log browser/modules/openLocationLastURL.jsm
fatal: ambiguous argument 'browser/modules/openLocationLastURL.jsm': unknown revision or path not in the working tree.

この場合、以下のように --follow オプションを付ける事で、削除したコミットを先頭にして、当該ファイルのログを見る事ができます。

$ git log --follow -- browser/modules/openLocationLastURL.jsm

openLocationLastURL.jsm が消えてました

全然気付かなかったけど、Firefox 29 の Australis の変更 (bug 953124) で openLocationLastURL.jsm が消え、一緒に chrome ウィンドウの gOpenLocationLastURL プロパティも消えてました。

2014年4月11日

Task.jsm と Promise.jsm

Task.jsm 内で Promise.jsm を使うようにするパッチ (Bug 887923) が Nightly (Firefox 31) に入ったようです。
現在 UnMHT は Task.jsm のコピー (Promise.jsm を使う版) を内部に持ってるわけですが、 これで次の ESR がリリースされてからはどちらも組み込みのものを使うようにできそうです。

2014年1月17日

Firefox 28 での DeferredTask.jsm の変更

DeferredTask.jsm が Firefox 28 でインターフェースというか内部の作りからまるまる変更され、Promise.jsmTask.jsm ベースになりました。
(という事をついさっき UnMHT の Mozmill のテストを Nightly 向けに走らせて知りました)
詳細は Bug 940408 を参照。
Firefox 27 までの DeferredTask.jsm は、以下のような使い方でした。

let helloTask = new DeferredTask(function() {
  Cu.reportError("Hello");
}, 2000);

// タスクを開始
helloTask.start();

setTimeout(function() {
  // 1 秒待ってからタスクを再度開始
  helloTask.start();
}, 1000);

// 3 秒後に Hello と表示される

Firefox 28 からは、同じ事をやるのに以下のように書くようです。

let helloTask = new DeferredTask(function() {
  Cu.reportError("Hello");
}, 2000);

// タスクを開始
helloTask.arm();

setTimeout(function() {
  // 1 秒待ってからタスクを取り止め
  helloTask.disarm();
  // タスクを開始
  helloTask.arm();
}, 1000);

// 3 秒後に Hello と表示される

おおよその対応は以下のとおり

Firefox 27 までFirefox 28 から
void start()void arm()
void cancel()void disarm()
void flush()Promise finalize()
boolean isPending()boolean isArmed
これは関数ではなく属性
なしboolean iRunning

arm()start() と違って遅延が追加されないとか、finalize()flush() と違って以降 arm() が呼べなくなるとか、細かい違いがあるので、コードを書き換える際には注意が必要です。

let helloTask = new DeferredTask(function() {
  Cu.reportError("Hello");
}, 2000);

// タスクを開始
helloTask.arm();

setTimeout(function() {
  // 1 秒待ってから disarm() を呼ばずにタスクを開始
  helloTask.arm();
}, 1000);

// 2 秒後に Hello と表示される

また、Task.jsm ベースになったので、タスクとしてジェネレータ関数を渡せるようになりました。

// 3 秒後に resolve するなんかイイカンジの関数
let waitThreeSecond = function() {
  let deferred = Promise.defer();
  setTimeout(function() {
    deferred.resolve();
  }, 3000);
  return deferred.promise;
}

let helloTask = new DeferredTask(function*() {
  yield waitThreeSecond();
  Cu.reportError("Hello");
}, 2000);
helloTask.arm();

// 5 秒後に Hello と表示される

この場合、タスク自体は 2 秒後から走り始めているので、3 秒後に arm() を呼んだ場合、これは最初の arm() とまとめられずに、arm() を呼んだ時点ではなくタスクの完了後から 2 秒後に再びタスクが走り始めます。
// 3 秒後に resolve するなんかイイカンジの関数
let waitThreeSecond = function() {
  let deferred = Promise.defer();
  setTimeout(function() {
    deferred.resolve();
  }, 3000);
  return deferred.promise;
}

let helloTask = new DeferredTask(function*() {
  yield waitThreeSecond();
  Cu.reportError("Hello");
}, 2000);
helloTask.arm();

setTimeout(function() {
  // 3 秒待ってからタスクを再度開始
  helloTask.arm();
}, 3000);

// 5 秒後と 10 秒後に Hello と表示され、

2014年1月2日

Nightly での nsIMemoryReporterManager の変更

UnMHT のメモリリークテストを動かしていたところ Nightly でテスト自体がエラーになる事態に、
という事で調べてみると nsIMemoryReporterManager.enumerateReporters が無くなったのでした。
詳細は Bug 947802 にあるようです。
どうやら全部非同期にするための変更らしいですヨ。

新しい方法は nsIMemoryReporterManager.getReports のようで、下のように書くと動きます。

let MemoryReporterManager
  = Cc["@mozilla.org/memory-reporter-manager;1"].
  getService(Ci.nsIMemoryReporterManager);

let handleReport = function(process, path, kind, units, amount,
                            description) {
  // 情報を集めるヤツ
};

let finishReporting = function() {
  // 完了したら呼ばれるヤツ
};

MemoryReporterManager.getReports(handleReport, null,
                                 finishReporting, null);

ちなみにこちらが Firefox 28 までのヤツ。
for (let r in XPCOMUtils.IterSimpleEnumerator(
  MemoryReporterManager.enumerateReporters(), Ci.nsIMemoryReporter)) {
  r.collectReports(handleReport, null);
}

そしてその前 (いつだっけ?) のヤツ。

for (let r in XPCOMUtils.IterSimpleEnumerator(
  MemoryReporterManager.enumerateReporters(), Ci.nsIMemoryReporter)) {
  handleReport(r.process, r.path, r.kind, r.units,
               r.amount, r.description);
}

for (let r in XPCOMUtils.IterSimpleEnumerator(
  MemoryReporterManager.enumerateMultiReporters(),
  Ci.nsIMemoryMultiReporter)) {
  r.collectReports(handleReport, null);
}