Javascript で実装した Ruby インタプリタ JSRuby 0.1 リリースしました。
1月からサイボウズ・ラボのオフィスが引っ越しました。新年から気分も新しくぶりぶり仕事します。よろしくです。
というわけでちょっとずつ作っていました Javascript で実装した Ruby インタプリタの "JSRuby" を一区切り付けるべくバージョン番号を付けてリリースしました。
- JSRuby Project Page (CodeRepos)
- http://coderepos.org/share/wiki/JSRuby
- JSRuby Test Page
- http://labs.cybozu.co.jp/blog/nakatani/jsruby/jsruby_test.html
ウリはパーサまで含めて js で実装しているので、与えられた Ruby スクリプトをブラウザ上でそのまま実行できることと、任意の Javascript のオブジェクトを渡して JSRuby 上でそのまま自然に扱えるので、特に個別にラッパーなどを実装しなくても js の様々なライブラリをそのまま使える(可能性がある)ことです。
(console)
簡単なフィボナッチ数列のプログラムですが、このとおり blog の記事の中で Ruby のコードが動きます。
全て JS だけで完結しているので、この実行部分を Bookmarklet 化すれば、任意のウェブページ上の Ruby スクリプトをそのブラウザ内で実行させることが出来ます(対応している機能だけですが)。
ブックマークレット:選択したrubyコードを実行
上記ブックマークレットのリンクをブックマークツールバーなどにドラッグし、下記コードをマウスで選択後、ブックマークレットを実行してみてください。rubyコンソールが開いて実行結果が表示されます(コンソールを消すときは
def fz(n) 1.upto(n){|x|puts ["FizzBuzz",x,0,"Buzz",0,0,"Fizz"][x**8%15%7]} end fz 20本ブックマークレットはコマンド入力欄も用意されているのでそのまま続けてスクリプトを逐次入力&実行ができます。
もちろんこのブックマークレットは本ブログ以外でも有効です。
闘うプログラマの友「どう書くorg」に投稿されている Ruby コードで、JSRuby にて基本無変更で動くものを下記にいくつかあげておきますので、それらで試してみてもらうのもおもしろいかもしれません。
- http://ja.doukaku.org/comment/2980/
- 関数定義しかないので、コンソールで diff [3,1,4,1,5,9,2] など入力して実行してみる。
- http://ja.doukaku.org/comment/1105/
- 1から10000だと終わらないので、最後の1行を除いて選択、bookmarklet でコンソールを開いたら、入力欄に実行範囲を 1から200に変えたスクリプトを入れてみる。
1.upto(200){|i| puts i if double_complete_number?(i) }
- http://ja.doukaku.org/comment/159/
- http://ja.doukaku.org/comment/142/
- ピラミッド表示。後者は関数になっているので、続けて pyramid 5 とか pyramid 9 とか入力して遊べます。
またもう一つのウリである Javascript との連携ですが、def で定義したメソッドは以下のように記述することで javascript 側から直接呼び出せます。
alert( ruby.call("fib", [8]) )これは上のフィボナッチ数列を計算するメソッドを呼び出す例です。実際、上のフィボナッチ数列のスクリプトをもう一度実行後、このページで FireBug のコンソールを開いてこの通り叩けば fib メソッドを呼び出せますので、試してもらえると楽しいかも。
こうして呼び出す Ruby メソッドの引数に Javascript の任意のオブジェクトを渡すことで、Ruby スクリプト側ではあたかも Ruby のオブジェクトであるかのようにそのオブジェクトのメソッドを呼び出すことが出来ます。
詳細は長くなってしまうので記事を改めることにして、とりあえずここでは簡単な例をごらんください。
実行すると画面を書き換えてしまう(全てのリンクに赤枠をつけてしまう)ので、見にくければリロードしてやってください(苦笑)。
window オブジェクトと document オブジェクトはそれぞれ $window, $document というグローバル変数にて最初から渡されており、それら Javascript のオブジェクトをこのような形で扱うことが出来ます。
JSRuby はまだ実装されていない機能も多く、目標である「どう書くorgに投稿されている Ruby コードの7割(≒ require を使っていないもの)が動く」にはまだまだ道のりが長いのですが、CodeRepos にてリポジトリが公開されていて、メソッドの実装追加などは簡単に行えるようになっていますので、多くの人にコミットしてもらえると嬉しいです。
参考:JSRuby 0.1 で実装済みの機能の一覧です。
- if ~ elsif ~ else ~ end
- def
- puts, p
- Array#<<
- Array#[], []=
- Array#each
- Array#inject
- Array#join
- Array#length
- Array#member?
- Array#new
- Array#push
- Array#reverse
- Numeric#+, -, *, /, %, **, ==, <=>
- Numeric#chr
- Numeric#to_s
- Numeric#upto
- String#+, *, ==
- String#[], []=
- String#center
- String#length
- String#reverse
- String#to_i
- Range#each
以下、戯れ言。
年末に yukoba さんが YARV インタプリタな HotRuby というのを作られて、JSRuby 作りながら「やっぱ YARV コンパイラ&VM を JS で書く方が正解なのかなー。でも VM を書くのはきっと楽しそうだけど、コンパイラを書くのはなんか楽しくなさそうだよなあ」と常々思っていたので全然くやしくなんかありません。すいません嘘です。比べてないですが、おそらく実行速度では敵わないと思います。
YARV ベースの ruby for javascript もいずれは出てくるだろうと思ってはいたんですが、あと半年は先かなあと思ってのんびりしてました(苦笑)。
ちなみに YARV の仕様全然知らないで言っているので、「VM書くのは楽しそう」「コンパイラ書くのは楽しくなさそう」も嘘かもしれません。あしからず。