ちなみに

火曜日の空は僕を押しつぶした。

RubyJSを試しました

RubyJSをためしてたらこんな時間で明日が心配な今日この頃です。

RubyJSはUnderscore.jsstring.jsみたいなJavaScriptのライブラリです。

特徴はRubyの機能をJSで実装しているところ。JS的な書き方を無視して、以下にRubyらしく書けるかに注力されています。RubySpecに準拠するように書かれているので、Rubyを普段使っている人には無意識に使えるようになっています。

使い方は簡単でライブラリを読み込んで、JSの任意のオブジェクトやプリミティブな値を RubyJS メソッドを使ってラップしてやります。この RubyJS メソッドが適切な RubyJS オブジェクトに変換してくれます。もちろん R というエイリアスが切られているので、こちらを使いましょう。

R 'hoge'  #=> RubyJS.String
R 1 #=> RubyJS.Fixnum
R [1, 2, 3, 4, 5] #=> RubyJS.Array

RubyJS メソッドで変換された RubyJS オブジェクトには、Rubyでおなじみのメソッドが定義されています。

do (R 'hoge').captalize #=> 'Hoge'
do (R 1).succ #=> 2
(R [1, 2, 3, 4, 5]).join ',' #=> "1,2,3,4,5"

また、とうぜんのようにチェインできます。

(R [1, 2, 3, 4, 5], true).map((x) -> x * x).join ',' #=> "1,4,9,16,25"

Enumerableのメソッドが出てくれば、とうぜんEnumeratorオブジェクトが返ってくるよね。ということでこれももちろん実装されています。

(do (R [1, 2, 3]).each_with_index).map (i, idx) -> [idx, i] #=> [[0,1], [1,2], [2,3]]

map に自然な感じで関数を渡していますが、RubyのBlockのような使い勝手になっています。といってもふつうのRubyistmapを使うときはSymbol#to_procを使うことがほとんどだと思います。以下のように書きましょう。

(R ['1', '2', '3'], true).map R.proc('to_i') #=> [1, 2, 3]
# (R ['1', '2', '3'], true).map (x) -> do x.to_i

いくつか注意点があって、Array#include?のような?がつく問い合わせ系のメソッドは?なしで実装されています。また、Rubyには破壊的なメソッドには!をつける文化がありますが、これは _bang をつけることで再現しています。

(R [1, 2, 3]).include 2 #=> true
a = R 'hoge'
do a.capitalize #=> 'Hoge'
a #=> 'hoge'
do a.capitalize_bang #=> 'Hoge'
a #=> 'Hoge'

また、+などのJSの構文とかぶるようなメソッドについては以下のように直接呼びだす必要があります。ちょっとダサいですね。

a = R 'hoge'
b = R 'piyo'
a['+'] b #=> "hogepiyo"

最後にRubyJSオブジェクトをJSのプリミティブ型に戻したいときは to_native を呼びます。

do ((R [1, 2, 3], true).map R.proc('succ') ).to_native #=> [ 2, 3, 4 ]

ちなみにRメソッドの第二引数をtrueにすることで、配列の各要素を再帰的に RubyJS オブジェクトに変換してくれます。逆に渡さないと変換してくれないので、ループで各要素を処理するときに、RubyJS オブジェクトが定義しているメソッドが使えなくてはまります。

こんなすてきなライブラリですが、minify しても 20KB くらいあるようで、PCサイトならともかくスマフォ向けのサイトならちょっと迷いどころです。必要なクラスだけ組込めるような感じになるとうれしいですね。

CoffeeScriptのコーディングスタイルは id:hitode909 に準拠しています。(see also: http://hitode909.hatenablog.com/entry/2013/01/20/182349)