Problems with Ruby.getClass

Hi,

I’ve ran into a little problem while starting off with JRuby embedding.
I’m using the following code fragment for getting the RubyClass of a
class:

String[] paths = new String[]{"."};
Ruby rt = JavaEmbedUtils.initialize(Arrays.asList(paths));
rt.executeScript(FileUtils.readFileToString(new File(“bar.rb”)),
“bar.rb”);
System.out.println("cl: "+rt.getClass(“Foo::Bar”));

Is the correct way to do it?

The problem is that Ruby.getClass method call returns null.
If I rename class Foo::Bar to Bar the method call returns a non-null
value.
I’m working with a code base that uses this naming convention for
subclasses and I can’t change the convention.

I’m using JRuby v1.6.7

marko

Hello,

On Mon, May 7, 2012 at 1:18 AM, Marko A. [email protected]
wrote:

Hi,

I’ve ran into a little problem while starting off with JRuby embedding.
I’m using the following code fragment for getting the RubyClass of a class:

String[] paths = new String[]{“.”};
Ruby rt = JavaEmbedUtils.initialize(Arrays.asList(paths));
rt.executeScript(FileUtils.readFileToString(new File(“bar.rb”)), “bar.rb”);
System.out.println("cl: "+rt.getClass(“Foo::Bar”));

If you evaluate just “Foo::Bar” , then, probably, you’ll get the class.

However, using JavaEmbedUtils is an old style. Now, you can use
JRuby’s embedding API.
For example:

import java.util.Arrays;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.PathType;
import org.jruby.embed.ScriptingContainer;

public class FooBar {

private FooBar() {
    ScriptingContainer container = new

ScriptingContainer(LocalContextScope.SINGLETHREAD);
String[] paths = {System.getProperty(“user.dir”) + “/ruby”};
container.setLoadPaths(Arrays.asList(paths));
String filename = System.getProperty(“user.dir”) +
“/ruby/bar.rb”;
container.runScriptlet(PathType.ABSOLUTE, filename);
Object obj = container.runScriptlet(“Foo::Bar”);
System.out.println(obj);
}

public static void main(String[] args) {
    new FooBar();
}

}

The code above, printed Foo::Bar .

Please go to web sites below when you use embedding API.

http://jruby.org/apidocs/

-Yoko

On Mon, Jun 4, 2012 at 11:45 AM, Yoko H. [email protected] wrote:

import org.jruby.embed.PathType;
container.runScriptlet(PathType.ABSOLUTE, filename);
Object obj = container.runScriptlet(“Foo::Bar”);
System.out.println(obj);
}

public static void main(String[] args) {
new FooBar();
}
}

Hi,

Thanks.
I read the RedBridge wiki page you mentioned and tried migrating my
code to use ScriptingContainer.
However, I’m having some problems figuring out how to use the newer API.
For example previously I used to instantiate Ruby object from Java
with the following code:

IRubyObject[] args = new IRubyObject[] {
// constructor arguments here
};
IRubyObject obj =
ruby.getClass(“Foo”).newInstance(ruby.getCurrentContext(), args,
Block.NULL_BLOCK);

How do I do this with ScriptingContainer?

Also, some parts of the API such as RubyHash.newHash seems to require
a Ruby object as a parameter.

ps. i noticed that i can get the class Foo::bar by calling
rt.getClass(“Foo”).getClass(“Bar”);

marko

On Mon, Jun 11, 2012 at 3:48 AM, Marko A.
[email protected] wrote:

import org.jruby.embed.LocalContextScope;
String filename = System.getProperty(“user.dir”) + “/ruby/bar.rb”;
Hi,
};
IRubyObject obj =
ruby.getClass(“Foo”).newInstance(ruby.getCurrentContext(), args,
Block.NULL_BLOCK);

How do I do this with ScriptingContainer?

Just using callMethod does this, but for clarity, I’ll paste whole code
here:

    ScriptingContainer container = new

ScriptingContainer(LocalContextScope.SINGLETHREAD);
String[] paths = {System.getProperty(“user.dir”) + “/ruby”};
container.setLoadPaths(Arrays.asList(paths));
String filename = System.getProperty(“user.dir”) +
“/ruby/bar.rb”;
container.runScriptlet(PathType.ABSOLUTE, filename);
Object obj = container.runScriptlet(“Foo::Bar”); // gets a
Foo::Bar class
System.out.println(obj);
Object foo = container.callMethod(obj, “new”); // gets an
instance of Foo::Bar
System.out.println(foo);

The code above prints:

Foo::Bar
#Foo::Bar:0x7eb9132a

Also, some parts of the API such as RubyHash.newHash seems to require
a Ruby object as a parameter.

You can use java.util.Map type object and put that to
ScriptingContainer. You can use Map type object like a Ruby Hash in
Ruby code. That’s easy to use Hash in both Java and Ruby sides. For
example:

    java.util.Map m = new java.util.HashMap();
    m.put("my_key", "my_value");
    container.put("m", m);
    container.runScriptlet("m[1] = 100; puts m.inspect");
    System.out.println(m.get(1L));

This prints out:

{1=>100, “my_key”=>“my_value”}
100

-Yoko

Hi,

Thanks a lot for your help, Yoko!
I managed to migrate my code to use theScriptingContainer API and it
seems to be working fine.

I’m planning on embedding JRuby in a multi-threaded (servlet
container) environment and I still have a few questions related to
this regarding thread-safety and usage patterns.
Here’re some code snippets and questions:

// Ruby rt + ScriptingContainer are initialized only once at startup
ScriptingContainer ruby = new
ScriptingContainer(LocalContextScope.CONCURRENT);
ruby.setLoadPaths(getRubyloadPaths());

can the ScriptingContainer instance be shared between threads or
should one be instantiated per thread?
what happens if ruby.setLoadPaths() is invoked after other threads
havestarted to use the ScriptingContainer?
when should Ruby libraries be loaded (require ‘foo’)? Can they be
loaded at any time? Will they be available to all threads? Are any
thread-safetyissues involved?

// each request is processed by a different thread.
// a new Ruby service instance is created to process each request.

// create/convert input parameters
Converter converter = new Converter(ruby);
Object[] args = new Object[] {
ruby.runScriptlet(":symbolX"),
converter.deepConvert(eventData) // see Converter class below
};

// create service instance
Object srv = ruby.runScriptlet(serviceName);
IRubyObject service = ruby.callMethod(srv, “new”, args,
IRubyObject.class);

// invoke service
ruby.callMethod(service, “process_event”, Object.class);

//----

public class Converter {
// …
public IRubyObject deepConvert(Object obj) {
// method implementation converts a complex Java data structure to
JRuby class instances like this:
RubyHash h = ruby.callMethod(ruby.runScriptlet(“Hash”), “new”,
RubyHash.class);
h.put(“foo”, “bar”);
// …
return h;
}
}

Does this look like a valid way to use the JRuby embedding API?

regards,

marko