linq.js ver.3.0.0-beta, メソッドlowerCamelCase化、など
- 2012-07-20
ずっとやるやる詐欺だったlinq.js ver.3ですが、ようやく始まりました!
トップページのボタンはstableのものになるので、DOWNLOADSタブからver.3.0.0-betaを選んでください。また、NuGetを使っている人はInstall-Package linq.js -Preで入ります。他にlinq.js-jQuery -Pre, linq.js-RxJS -Pre, linq.js-QUnit -Preなどり。
lowerCamelCase化
はい。ようやくJavaScriptらしくなりました。UpperCamelCaseにはC#っぽいとか、キーワードで衝突しなくなるとか、ちょっとした利点はなくもないのですが、そもそも.NETっぽくないほうがいい、というかJavaScriptの世界にちゃんと馴染ませたいという思いのほうが強い。そして、.NETの人以外にも使って欲しくて。
Enumerable.range(1, 10)
.where(function(x){ return x % 2 == 0})
.select(function(x){ return x * x});
当然ながら超破壊的変更です。ver.2までのコードは一切動かなくなります。やりすぎですが、しょうがない。痛くてしょうがないけれどしょうがない。さて、ならばとついでにメソッド名の見直しもしました。
Return -> make
CascadeBreadthFirst -> traverseBreadthFirst
CascadeDepthFirst -> traverseDepthFirst
BufferWithCount -> buffer
ToString -> toJoinedString
Do -> doAction
Let -> letBind
MemoizeAll -> memoize
Catch -> catchError
Finally -> finallyAction
ToJSON -> toJSONString
これを機に、というかこういう機会じゃないとやれないですから。toStringやtoJSONは、上書きしてしまうとマズいので別名にしています。toStringは、まあそのままなので分かると思うのですが、toJSONのほうは、JSON.stringifyで特別扱いされるメソッドなので、こっそり注意が必要なんですね、というか実際ハマッて気づくのに時間かかりました。
extendTo
prototype.js以降、prototype拡張は悪、でしたが、最近のJavaScriptはfor inで列挙しない形での拡張(Object.definePropertyでenumerable:falseにする)が可能になっています。それを全面に押し出したSugarといったライブラリもあり、確かに便利なのですよね。
さて、linq.jsでは配列などをLINQで扱うためにEnumerable.fromで包んでやる必要があって面倒でしたが、配列からそのままselectとかwhereとかが生えていれば、便利、ですよね?なので、任意に拡張できるようにしました。
// Arrayを拡張する
Enumerable.Utils.extendTo(Array);
[1, 3, 10, 1000].where("$%2==0").select("$*$");
Enumerable.Utils.extendToを一度呼べば、from不要で直接LINQのメソッドを呼ぶことができます。もしブラウザがObject.definePropertyに対応していなければ、その時はprototypeを直接拡張しています。
さて、LINQのメソッド名とネイティブのメソッド名が被っている場合は、ネイティブのメソッド名を優先して、上書きはしません。例えばjoinとか、concatとか。その場合はByLinqがメソッド名の末尾につきます。joinByLinq、など。
// 名称が被るものはByLinqというプリフィックスがつく
[1, 3, 10].reverseByLinq();
// もしくはasEnumerableメソッドを呼んであげればLINQのメソッドのみになります
[1, 10, 100].asEnumerable().forEach(function(x, index){alert(x + ":" + index)});
forEachなどは古いブラウザではそのまま、新しいブラウザではforEachByLinqになる、といったようにブラウザ互換性がなくなるので、個人的にはByLinqの形で呼ぶよりかは、asEnumerableを使うことのほうをお薦めします。
Visual Studio 2012でのIntelliSense超拡張
VS2012でlinq.jsを使うと、ただでさえ充実していたIntelliSenseが更に超補完されます。どのぐらい補完されるか、というと、selector関数でオブジェクトの候補が並んでしまうぐらいに。
もはや完全にC#。あまりの快適さにチビる。勿論、↑の図ではFooは文字列なので、x.Foo.で文字列のメソッド候補がIntelliSenseに並びます。動的言語とは思えない超補完っぷりがヤバい。そして入力補完が最大限に活きるように設計されているLINQなので、組み合わさった時の快適度は半端ない。
Chaining Assertion for QUnit
ユニットテストを書く際に、equal(actual, expected)と書くのが嫌いでした。どちらがactualなのかexpectedなのか一瞬悩むし、そもそも外側から包むのがかったるくて。かといってshouldといった、英語的表現なのも冗長なだけで全く良いとは思っていませんでした。そこでC#ではChaining Assertionといった、actual.Is(expected)でアサートが書けるライブラリを作ったのですが、それをJavaScript用に移植しました。
// 流れるように.isと打ち込むだけ
Math.pow(10, 2).is(100); // strictEqual(Math.pow(10, 2), 100)
// コレクションに対する適用は可変長にカンマ区切りで値を並べるだけ。勿論、配列にも使えます。
Enumerable.rangeTo(10, 15, 2).is(10, 12, 14); // deepEqual(Enumerable.rangeTo(10, 15, 2).toArray(), [10, 12, 14])
// LINQと組み合わさることでコレクション系のチェックが遥かに容易になる!
[1, 5, 10].all("$<12").isTrue(); // collection assertion with linq.js!
といった感じに書けて、超楽ちんです。使うにはlinq.qunit.jsを別途読み込んでください。
その他
createEnumerable, createEnumerator, createLambdaといった、自作Enumerableメソッドを作るための道具を外部公開するようにしました。是非作っちゃってください。
Enumerable.Utils.createLambda
Enumerable.Utils.createEnumerable
Enumerable.Utils.createEnumerator
更に、メソッドも追加されています。
Enumerable.defer
asEnumerable
merge
choose
isEmpty
distinctUntilChanged
weightedSample
log
それらの細かい使い方などは追々書いていきます。また、merge, zip, concatは複数のシーケンスを引数に受け取れるようになりました。
そして、C#では、以前にneue cc - LINQのWhereやSelect連打のパフォーマンス最適化についてという記事を書いた通り、Where連打やSelect連打、それにWhere->Selectといったよくあるパターンに対して最適化が入っているのですが、それをlinq.jsでも再現しました。なので、Where連打などによるパフォーマンス劣化が抑えられています。また、頻出パターンのWhere->Selectで高速化されたのはかなり大きいと思っています。
それに加えてrange, rangeDown, rangeToといったよく使う生成関数の速度を大幅に上げました(以前はtoInfinity().take()で生成していたのを、独自生成に変更したため)。
なので全体的にパフォーマンスも向上しています。
それと最後に、jQueryのプラグインとしてのものは今回からやめました。なんか混乱するし意味ないな、と思ったので、jQueryとの連携はlinq.jquery.jsによるtoEnumerable/tojQueryを追加するファイルのみとなっています。RxJSに関しても最新版のRxJSと連携できるようにしました(linq.rx.js)
今後
VS2012に対するIntelliSenseの充実化がまだ1/5ぐらいしか出来ていないので、それの充実が優先です。あと、リファレンスやサンプルが書けてないので追加。それらが出来たら、いったんver.3として正式公開します。プログラミング生放送勉強会 第17回@品川 #pronama : ATNDで話すつもりなので、その日、8/25までには正式公開を目指します!というわけで是非是非聞きに来てください。
あ、あとnode.js用にnpm公開も、ですね。