I've been playing with the JRuby Direct Embedding and a lot of my
current work relies on passing Ruby blocks to a Java process that will
run them using the JRuby runtime.
I'm seeing some NPEs in what it seems to be very simple Ruby blocks. For
example the following will fail:
RubyInstanceConfig config = new RubyInstanceConfig();
config.setCompatVersion(CompatVersion.RUBY1_9);
runtime = Ruby.newInstance(config);
evaluator = JavaEmbedUtils.newRuntimeAdapter();
threadContext = ThreadContext.newContext(runtime);
RubyProc proc = (RubyProc)eval("proc { puts 'Hello World' }");
proc.getBlock().call(threadContext);
While a more complex example like the next one below, works:
// Parameters
RubyFixnum a = new RubyFixnum(runtime, 40);
RubyFixnum b = new RubyFixnum(runtime, 2);
RubyProc proc = (RubyProc)eval("proc { |a, b| a + b }");
Integer result = (Integer) proc.getBlock().call(threadContext, a,
b).toJava(Integer.class);
assertEquals(42, result.intValue());
Yet, a similar example concatenating strings fails:
RubyString a = RubyString.newString(runtime, "Hello ");
RubyString b = RubyString.newString(runtime, "World");
RubyProc proc = (RubyProc)eval("proc { |a, b| a + b }");
String result = proc.getBlock().call(threadContext, a,
b).asJavaString();
assertEquals("Hello World", result);
But again, more esoteric examples like eval-ing a class in Ruby,
creating an instance and then passing it to another ruby proc works:
RubyObject param = (RubyObject)eval("class Foo; def bar; 'foobar'; end;
end; Foo.new");
IRubyObject[] args = { param };
RubyProc proc = (RubyProc)eval("->(x;obj) { x }");
RubyObject result = (RubyObject) proc.getBlock().call(threadContext,
args);
String val = result.callMethod("bar").asJavaString();
assertEquals(val, "foobar");
But if I try to invoke a method of the passed parameter it fails:
RubyObject param = (RubyObject)eval("class Foo; def bar; 'foobar'; end;
end; Foo.new");
RubyProc proc = (RubyProc)eval("proc { |obj| obj.bar }");
RubyObject result = (RubyObject) proc.getBlock().call(threadContext,
param);
String val = result.asJavaString();
assertEquals(val, "foobar");
So, it seems that if I try to do anything to/with the passed parameters
things go bananas, and as you can see in some of the examples above
calling puts on anything, event a literal string blows chunks.
I'm attaching a Maven project with a JUnit
test that shows the problems that I'm running into in case anyone is
interested. Of course, there is always the possibility that I'm doing
something supremely stupid.
Thanks,
Brian
on 2012-10-19 17:26
on 2012-10-19 19:08
Hello,
I'm not sure you dare to avoid using ScriptingContainer. But, just in
case, you don't know JRuby's embedding API.
What you are trying to can be done like below using ScriptingContainer.
ScriptingContainer container = new ScriptingContainer();
RubyProc my_proc = (RubyProc)container.runScriptlet("proc {
puts 'Hello World' }");
container.callMethod(my_proc, "call");
my_proc = (RubyProc)container.runScriptlet("proc { |a, b| a + b
}");
Object ret = container.callMethod(my_proc, "call", 40, 2);
System.out.println(ret);
ret = container.callMethod(my_proc, "call", "Hello ", "World");
System.out.println(ret);
This code prints:
Hello World
42
Hello World
Best,
-Yoko
on 2012-10-20 18:35
Yoko, I was purposely avoiding the ScriptingContainer thinking I was going to eventually hit a limitation with it so I opted for what I thought was a lower-level API. I've rewrote my library to use the ScriptingContainer and things work as expected. I also wrote the unit tests in the previously included Maven project using the ScriptingContainer and all tests pass too. Thanks for the suggestion. Cheers, Brian Yoko Harada wrote in post #1080466: > Hello, > > I'm not sure you dare to avoid using ScriptingContainer. But, just in > case, you don't know JRuby's embedding API. > > What you are trying to can be done like below using ScriptingContainer. > > ScriptingContainer container = new ScriptingContainer(); > RubyProc my_proc = (RubyProc)container.runScriptlet("proc { > puts 'Hello World' }"); > container.callMethod(my_proc, "call"); > my_proc = (RubyProc)container.runScriptlet("proc { |a, b| a + b > }"); > Object ret = container.callMethod(my_proc, "call", 40, 2); > System.out.println(ret); > ret = container.callMethod(my_proc, "call", "Hello ", "World"); > System.out.println(ret); > > This code prints: > > Hello World > 42 > Hello World > > Best, > -Yoko
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.

