Embedding Q: calling ruby lambda's from java

Hi,

I am new to both JRuby and Ruby itself, so excuse me if I stumble a bit
here. I had previously been using Jython and way in the distant past
Rhino. In both of these environments I could evaluate some script to
return a reference to a function (or some sort of invokable object).
The pseudo code is:

ScriptingEngine engine = new ScriptingEngine (…);

fun = engine.eval ()

fun.invoke (3.0, 1.2)

The point of the above was that it is generally much faster to
evaluate in this form (particularly if I am evaluating at high
frequency), than doing something like:

engine.eval ()

engine.eval (“foo(3.0, 1.2)”)

The context of this “requirement” is that I want to embed some code
fragment into a configuration, such as:

lambda (| a,b,c | aaa + 4bb + 5*c)

evaluate it and be able to call it thousands of times within java.

I am using the “core” interface, i.e. ScriptingContainer. Appreciate
feedback on how to accomplish this. I don’t mind having a temporary
solution should there not be a direct one right now.

For instance, could I take the code in the configuration and wrap it
into a class that could be called from java numerous times without
calling runScriptlet?

That is another thing I am not clear about. In Jython or Rhino I can
extend a java interface. I have seen how that is done within JRuby as
well. However, I am not sure how to call such a class from the java
side. I note that there are methods in ScriptingContainer such as:

callMethod(receiver, methodName, args, returnType)

Many thanks!

Jonathan

Hi Jonathan,

I think you are tr8dr on #jruby IRC channel, right?
I’m not sure what’s wrong with my chat client, but, today, I couldn’t
write at all. I got “ Error(404): #jruby Cannot send to
channel.” Sorry about this.

On Tue, Feb 2, 2010 at 1:47 PM, Jonathan Shore
[email protected] wrote:

I am new to both JRuby and Ruby itself, so excuse me if I stumble a bit
here. I had previously been using Jython and way in the distant past
Rhino. In both of these environments I could evaluate some script to
return a reference to a function (or some sort of invokable object). The
pseudo code is:
ScriptingEngine engine = new ScriptingEngine (…);

fun = engine.eval ()

fun.invoke (3.0, 1.2)

OK, so you want to evaluate a function/class once and invoke it many
times. Probably, examples

http://kenai.com/projects/jruby/pages/RedBridgeExamples#Method_Call
http://kenai.com/projects/jruby/pages/RedBridgeExamples#Class_Method_Call

will help you to know how to write.

The point of the above was that it is generally much faster to evaluate in
this form (particularly if I am evaluating at high frequency), than doing
something like:
engine.eval ()

engine.eval (“foo(3.0, 1.2)”)

Yes. Evaluated function/class is cached on Ruby runtime, so just
invoking methods are faster than parsing and evaluating each time.

The context of this “requirement” is that I want to embed some code fragment
into a configuration, such as:
lambda (| a,b,c | aaa + 4bb + 5*c)
evaluate it and be able to call it thousands of times within java.

Ok. I think you need a block in the argument of callMethod method.
ScriptingContainer has a method of that type, but, unfortunately, that
method is useless now. The method accepts org.jruby.runtime.Block
object. Since JSR223 doesn’t have such method, I haven’t thought much
about that method. Will you file this at
http://jira.codehaus.org/browse/JRUBY? so that I don’t forget this
issue. Also, would you attach sample code you want to evaluate? That
will help to know how should it be implemented.

I am using the “core” interface, i.e. ScriptingContainer. Appreciate
feedback on how to accomplish this. I don’t mind having a temporary
solution should there not be a direct one right now.
For instance, could I take the code in the configuration and wrap it into a
class that could be called from java numerous times without
calling runScriptlet?

Compiling code fragment to real java class… this might work.

That is another thing I am not clear about. In Jython or Rhino I can
extend a java interface. I have seen how that is done within JRuby as
well. However, I am not sure how to call such a class from the java side.
I note that there are methods in ScriptingContainer such as:
callMethod(receiver, methodName, args, returnType)

Probably,

http://kenai.com/projects/jruby/pages/RedBridgeExamples#Interface_Implementation

is what you want to do.

-Yoko

Many thanks!
Jonathan

http://tr8dr.wordpress.com/


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Feb 2, 2010, at 3:01 PM, Yoko H. wrote:

The context of this “requirement” is that I want to embed some code fragment
into a configuration, such as:
lambda (| a,b,c | aaa + 4bb + 5*c)
evaluate it and be able to call it thousands of times within java.

It looks like lambda’s (or procs) can be “magically” mapped to a java
interface that contains a function with the correct number of arguments:

Function3.java:
public interface Function3
{
Object f (Object a, Object b, Object c);
}

Test.java
final String code = “lambda {|a,b,c| a*a+b+c }”;

Object out = script.runScriptlet(code);
Function3 test = script.getInstance(out, Function3.class);
Object r = test.f (3.0, 2.0, 1.0);

Well, that solves my problem!

Thanks

Jonathan

Thanks harada-san. I figured part of this out after I posted. See
below:

On Feb 2, 2010, at 3:01 PM, Yoko H. wrote:

OK, so you want to evaluate a function/class once and invoke it many
times. Probably, examples

http://kenai.com/projects/jruby/pages/RedBridgeExamples#Method_Call
http://kenai.com/projects/jruby/pages/RedBridgeExamples#Class_Method_Call

will help you to know how to write.

Thanks.

about that method. Will you file this at
http://jira.codehaus.org/browse/JRUBY? so that I don’t forget this
issue. Also, would you attach sample code you want to evaluate? That
will help to know how should it be implemented.

I had tried:

String code = “lambda {|a| a*a }”;

ScriptingContainer script = new ScriptingContainer();
Object out = script.runScriptlet(code);

script.callMethod(out2, null, new double[] {3.0}, Double.class);

That did not work (as expected). However I noticed that “out” is of
type “RubyProc”. The RubyProc object has a method:

IRubyObject ← call(ThreadContext context, IRubyObject[] args)

This looks like an internal method. I assume that the thread context
would be available in the ScriptingContainer. As for creating
IRubyObjects, is there a utility function that will take a java Object
or Object[] and generate the corresponding IRubyObject or IRubyObject[]?

As a user can I grab the thread context and wrap/unwrap the objects
appropriately so as to be able to use this?

Thanks!

Jonathan

Ok. I think you need a block in the argument of callMethod method.
ScriptingContainer has a method of that type, but, unfortunately, that
method is useless now. The method accepts org.jruby.runtime.Block
object. Since JSR223 doesn’t have such method, I haven’t thought much
about that method. Will you file this at
http://jira.codehaus.org/browse/JRUBY? so that I don’t forget this
issue.

Was this ever filed/should it still be?
Anybody know how to pass in a pure java “something” as a ruby method
block parameter?
Thanks!
-roger-

On Tue, Feb 2, 2010 at 2:35 PM, Jonathan Shore
[email protected] wrote:

Ok. I think you need a block in the argument of callMethod method.
String code = “lambda {|a| a*a }”;
ScriptingContainer script = new ScriptingContainer();
Object out = script.runScriptlet(code);

script.callMethod(out2, null, new double[] {3.0}, Double.class);

lambda return a Proc instance in Ruby:

irb(main):001:0> lambda {}
=> #Proc:0x00000000@:1(irb)

You can then change this to:

script.callMethod(out, “call”, 3.0);

since Proc can be invoked via call. (the Double.class is unneccesary
on trunk but needed for 1.4.0 since we have since made that argument
optional),

-Tom

Thanks!
Jonathan


blog: http://blog.enebo.com twitter: tom_enebo
mail: [email protected]


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email