Rubinius の変なところ:モジュールまわりをいじっていて気付いたところ篇
keita% ./shotgun/rubinius -e "module ::A; end" An exception has occurred: Missing or uninitialized constant: A (NameError) Backtrace: Module(Class)#const_missing at kernel/core/module.rb:713 Object#__script__ {} at (eval):1 Kernel(Module)#eval at kernel/core/eval.rb:67 Compile.execute at kernel/core/compile.rb:74 Object#__script__ at kernel/loader.rb:277
そこで参照しないで下さいよ!もちろん MatzRuby では次のように大丈夫。
keita% ruby -e "module ::A; end; A" #=> A
このせい(なのかどうか分かりませんが)で他もとっても変。
keita% ./shotgun/rubinius -e "module B; end; p module A; module ::B; self; end; end" B::B # MatzRuby では B
うーん、なぜ ::B が B::B になるのか。ひょっとして、"::B"で一度 B を参照して、その中でさらに B を定義しようとしてるのでしょうか。まさに予想外の振舞いです。さらに予想外なのはこれを B をモジュールからクラスに変えると結果が違うこと。
keita% ./shotgun/rubinius -e "class B; end; p module A; class ::B; self; end; end" A::B # MatzRuby では B
なぜそこは B ではなく A の下にいれるわけ(これを見るとさっきのモジュールの場合の予測ははずれていそうです)。せめてどちらかだけでも正しく振る舞ってくれると嬉しいのですが、これはやっかいな予感がします。
そしてもう一つ。
keita% ./shotgun/rubinius -e "module A; end; class A; end; p A.class" An exception has occurred: constant is not a class (TypeError) Backtrace: Object#__script__ {} at (eval):1 Kernel(Module)#eval at kernel/core/eval.rb:67 Compile.execute at kernel/core/compile.rb:74 Object#__script__ at kernel/loader.rb:277 keita% ./shotgun/rubinius -e "class A; end; module A; end; p A.class" Class
というわけで module → class の場合にはちゃんとエラーになるのに、class → module の場合はエラーになりません。あとエラーメッセージの"constant"の部分ってひょっとして"A"を入れようとしてミスしているのではないでしょうか。
あとついでに言うと Module.nesting がちゃんと動きません。これは spec が用意されていますのでそちらで確認してみて下さい。
以上のように、Rubinius はそれっぽく動いているようで、案外こういう基本的な部分がまだまだのようです。直したいところですが、"::B"の解釈が狂ってるの、さすがに直すの大変そうな予感がします。簡単なものはパッチを作って送りたいと思います。
追記
この辺をいじるためには Rubinius の全体像をきちんと把握する必要がありそうです。だというのに Rubinius の VM ってなんか今新しいのを作ってる真っ最中みたいで、とても間が悪い感じ。shotgun 以下のはなんとなく分かったのですが、これは古い方なんですよね。新しい VM は C++ で書かれていて、ビルドしてみたら LLVM が云々言ってて、全く手が出せそうにありません。
というか新しいVM、情けないことに動かし方からして全然分かりません。ドキュメントどこ?
そんな感じなので Rubinius はしばらく様子見ということにしておこうかと思いました。なんてこった VMだけじゃなくて kernel 以下のコードもごっそり変わってたりするじゃないのさ!じゃあひょっとして送った Module#include のパッチも意味なかった?