JRuby覚え書き(JavaからRubyへのアクセス方法まとめ)

準備

import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.embed.ScriptingContainer;
import org.jruby.runtime.ThreadContext;

ScriptingContainer container = new ScriptingContainer();
Ruby ruby = container.getProvider().getRuntime();

Rubyスクリプトの評価

文字列でもファイルでも評価が可能
runScriptletは最後に評価されたものが返される - 関数定義なら関数のシンボル - クラス定義ならクラス? - 計算式なら計算結果 が返る。
callMethodに渡すreceiverはインスタンスメソッドを呼ぶ時以外はnullでも良さそう

ret = container.runScriptlet(JRubyTest.class.getResourceAsStream("define_medhod.rb"), "define_medhod.rb");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:hello class:class org.jruby.RubySymbol
ret = container.runScriptlet(JRubyTest.class.getResourceAsStream("define_class.rb"), "define_class.rb");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:method class:class org.jruby.RubySymbol
ret = container.runScriptlet("0x1111 + '5'.to_i + 6.8 ");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:4380.8 class:class java.lang.Double

関数の実行

第一引数のReceiverはインスタンスメソッドでなければnullでよさそう
RequestクラスはObject.classを指定しても適切なクラスにキャストしてくれているぽい
ただしRubyの戻りにLongを設定したのにStringを指定するとキャストエラーになる

ret = container.callMethod(null, "hello", 1, "HelloA", new ArrayList<>()); // => called Method 'hello' arg1:1 arg2:Hello arg3:[]
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:String value class:class java.lang.String
ret = container.runRubyMethod(Object.class, null, "hello", 1, "HelloB", new ArrayList<>()); // => called 'hello' arg1:1 arg2:HelloB arg3:[]
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:String value class:class java.lang.String

変数の設定

container.put("local_val", 1);
printf("ret:%s class:%s \n", container.get("local_val"), container.get("local_val").getClass()); // => ret:1 class:class java.lang.Integer
container.put("$global_val", 2);
printf("ret:%s class:%s \n", container.get("$global_val"), container.get("$global_val").getClass()); // => ret:2 class:class java.lang.Integer
container.put("CONSTANT", 3);
printf("ret:%s class:%s \n", container.get("CONSTANT"), container.get("CONSTANT").getClass()); // => ret:3 class:class java.lang.Integer

クラスの特異関数の呼び方

ret = container.get("こうたの弟子");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:こうたの弟子 class:class org.jruby.RubyClass
ret = ((RubyClass)ret).callMethod("clsMethod"); // => called clsMethod!!
printf("ret:%s class:%s \n", ret, ret.getClass());

インスタンスの生成

getでクラスオブジェクトを取得し、newInstance関数を実行することでインスタンスが生成できる

ret = container.get("こうたの弟子");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:こうたの弟子 class:class org.jruby.RubyClass
ret = ((RubyClass)ret).newInstance(ThreadContext.newContext(ruby) , null);
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:#<こうたの弟子:0x3e8b8f0> class:class org.jruby.RubyObject

メンバ変数の操作

ret = container.get("こうたの弟子");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:こうたの弟子 class:class org.jruby.RubyClass
ret = ((RubyClass)ret).newInstance(ThreadContext.newContext(ruby) , null);
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:#<こうたの弟子:0x3e8b8f0> class:class org.jruby.RubyObject
container.put(ret, "@memb", 99);
printf("ret:%s class:%s \n", ret, container.get(ret, "@memb"), container.get(ret, "@memb").getClass()); // => ret:#<こうたの弟子:0x4b98225c> class:99

インスタンスメソッドの呼び方

ret = container.get("こうたの弟子");
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:こうたの弟子 class:class org.jruby.RubyClass
ret = ((RubyClass)ret).newInstance(ThreadContext.newContext(ruby) , null);
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:#<こうたの弟子:0x3e8b8f0> class:class org.jruby.RubyObject
ret = container.callMethod(ret, "method", Object.class); // => instance method
printf("ret:%s class:%s \n", ret, ret.getClass()); // => ret:called class:class java.lang.String