Passing Ruby Blocks for a Java Process to execute

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

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

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 H. 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