2007年 12月 07日

Rhino でテスト

いろつき!

ブラウザの機能使わないテストだと rake でテストできていいなぁ

どうやら

おれは、どうも、中身より、API のデザインのほうが気になるみたいだ。中身はもちろん、すごくおもしろいけど、中身がどうよくても、API がよくなければ使えない。そのうえで、中身、と、それと API をふくめた哲学が一体となって、美しいライブラリ/フレームワークになるんだなぁ。

これは別に比喩でもなんでもなくて、他のことに言いかえると意味が剥れてしまうようだ。中身より外見のほうが気になるってのはちがうし


そして、頭がわるいこともあって、できるだけシンプルなデータ構造と、できるだけシンプルな動作がすきだ。だから、そのために多少の高速性が犠牲になっても、べつにいいと思ってる。そうもいかないこともかなり多いけど、やっぱりそういうところをいじろうとすると、戸惑う。むずかしい。高速性より、理解のしやすさ、読みやすさ、がおれのなかでは、かなり優先順位が高い。綺麗なソースがすきだ。どうしてもそうだ。

あああ

もっとあたまがよければ、もっとよくいきれたのになぁ……

JS のドキュメンテーションツール

JSDoc Toolkit がよさそうなんだけど、どっちにしても Java Doc 形式のコメントが好きになれないので使う気がおきなかった……(ここでまた慣れるか、オレオレ文法でいくかで悩む。でも @return とか @param とかすごいダサく感じる……)

MochiKit は python の docutil (?) とかいうのをつかってるみたいだ。スクリプトのほうには id だけつけて、rst ? っていうのにドキュメントがまとまってる。よくわかんない。

あと MochiKit はスクリプトの圧縮に rhino をつかってるっぽい (custom_rhino.jar/js.jar) けど詳細がよくわからない。Rhino/Spidermonkey は JS 内部から JS トークナイザにアクセス (Ripper みたいに) できたらいいのに……Rhino のほうは内部メソッド叩いたらできるんかなぁ。


それとドキュメントをソースコードに書くべきかどうかがいまいち迷う。RDoc はソースコードにまぜて書くけど、見通しが悪くなるんだよなぁ。でも最低限の使いかたはコメントとして近くに書いておきたいし、挙動を変更したらすぐ書きかえたいから、近くにあるのは便利だ。

あとドキュメントに実装を簡単に見れるしくみが絶対必要だと思う。長い英語よむぐらいならソース見たほうが理解できるし、ソース見てからドキュメント読むとよめるようになるし……

Twisted

正直にいうとごくごく最近まで MochiKit Deferred の由来が Twisted (Pythonの非同期ライブラリ) からきていると知らなかった……
Python のマルチスレッドってどうなってるんだろう。threading/thread とかがヒットする。

Ruby のスレッドはなんか頭つかわなくても書けるなぁ。なんでだろう……あと Ruby で Deferred は必要か、っていうのが微妙に最近ひっかかる。なんで Ruby には Deferred がないんだろう (つまり、なんでなくてもいいやって思えるんだろう)

JS だとスレッドがなくて、しかもいちいちブラウザに処理をもどさないと固まってしまうから Deferred がすごい威力を発揮するけど、スレッドがあったときに、Deferred はどう活躍するんだろう。(Python にはスレッドがあるっぽいけど、なんで Deferred が必要になったんだろう)

Ruby だと非同期な HTTP GET をやるなら

require "open-uri" # net/http はめんどいから

t = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end

p t.value

みたいになって、複数あつめてやるのをスレッドつかってかくと

require "open-uri"

t1 = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end

t2 = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end


[t1.value, t2.value].each do |i|
	p i.length
end

さらにつなげていこうとすると大変? そうでもない気がする。うーん

最初から非同期なやつだと (ぱっとでてこない)、めんどいかなぁ……

いやいやそもそも Deferred は非同期なやつをほげほげするやつなんだ。

Ruby だと非同期なメソッドがあんまりないから気にならないのかなぁ。

Greasemonkey スクリプトの構成

なんでこんなふうに書いてるの? って感があるのかもしれないから、いちおうかいとくよ!

(function () { // なんか GM ではいらなくなってるっぽいけど、一応かこう

// メインの処理
foobar...


// ユーティリティ関数たち
function $X () {
}


})();

って感じで書いてる。メインの処理、その GM で一番重要なところをできるだけ上に書きたい (ただし、うえから順に読んでも理解できるように)。なのでユーティリティ関数とかは関数式ではなく関数宣言で書く。宣言で書いた場合はあとに書いても前のほうで参照できる。

foo();

function foo () {
    foobar();

    function foobar () {
    }
}

// baz(); //=> これはできない

var baz = function () {
};

baz();

でも、これだと prototype への代入とかをするのをうしろに書けない。そういうときは、

with (F()) {
    var baz = new Foo();
}

function F () {
    function Foo () {
        return (this instanceof Foo) ? this.init() : new Foo();
    }
    Foo.prototype = {
        init : function () { }
    };

    var foo = {};
    foo.Foo = Foo;
    return foo;
}

とかやるとうまいこと分離できるぽい。

JSDeferred の jsdeferred.userscript.js は、コピペ用のコード ( http://svn.coderepos.org/share/lang/javascript/jsdeferred/trunk/jsdeferred.userscript.js ) を生成していて、これを最後にコピペして with をつかえば綺麗にかけるようにようにした。

with (D()) {
    next();
}

// コピペ
function D () {

}