fooというrubyのメソッドに、FooというJavaクラスのインスタンスを渡す例です。
----
import java.util.ArrayList;
import java.util.Map;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.javasupport.JavaembedUtils;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
public class JRubyTest {
private static class Foo {
public String getFoo() {
return "foo";
}
}
public static void main(String[] args) throws Exception {
Ruby ruby = JavaembedUtils.initialize(new ArrayList<String>());
RubyRuntimeAdapter evaler = JavaembedUtils.newRuntimeAdapter();
String ls = System.getProperty("line.separator");
String script =
"def foo(arg)" + ls +
" puts arg.foo" + ls +
"end";
evaler.eval(ruby, script);
Map<String, DynamicMethod> map = ruby.getClass("Object").getMethods();
DynamicMethod method = map.get("foo");
ThreadContext ctx = ruby.getCurrentContext();
RubyClass obj = ruby.getObject();
IRubyObject arg = JavaembedUtils.javaToRuby(ruby, new Foo()); //[A]
IRubyObject rv = method.call(ctx, obj, null, "foo", arg); //[B]
System.out.println(rv);
}
}
----
ポイントは上の例の最後の方の[A]と[B]の2点あります。
[A]でJavaのオブジェクトをRubyのオブジェクトに変換しています。
Javaのオブジェクトのメソッドはいい感じでRubyのメソッドに変換される模様です。
[B]では、JRubyのランタイムから取得したメソッドfooを表すメソッドオブジェクトの呼び出しを行っています。
このcallメソッドのシグネチャは以下のようになっております。
-----
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name, IRubyObject arg)
-----
このメソッドの引数の意味がわからなくてちょっとはまりました。
いまのところ、適当な引数を渡してみたらなんとか動いた、というのが正直なところです。
第2引数と第3引数で、そのメソッドがそのオブジェクトが属するオブジェクトとモジュールを決定します。これらは、メソッド内で引数のメソッド以外のメソッド呼び出しをするときに必要になってきます。
これらの引数にnullを渡して、その呼び出し先のメソッドで上記の例のようにputsとかを呼び出すと、ぬるぽになります。
第4引数も何に使われるのか謎なのですが、多分メソッド名です。
DynamicMethod自体は自分の名前を持ってないようだったので。。。
第5引数以降はRubyのメソッドに渡す引数です。
callメソッドの実装を読み解こうとも試みたのですが、ひどくややこしいことになっていたので、それはいずれ。。