Forum: JRuby Problems with Ruby.getClass

D4c223beb610f1e5baa56a0b764e24a9?d=identicon&s=25 Marko Asplund (Guest)
on 2012-05-06 18:19
(Received via mailing list)
Attachment: bar.rb (41 Bytes)
Attachment: foo.rb (17 Bytes)
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
E184bc2347f90dd61b509de6eb43a8b6?d=identicon&s=25 Yoko Harada (Guest)
on 2012-06-04 10:47
(Received via mailing list)
Hello,

On Mon, May 7, 2012 at 1:18 AM, Marko Asplund <marko.asplund@ixonos.com>
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/
https://github.com/jruby/jruby/wiki/RedBridge

-Yoko
D4c223beb610f1e5baa56a0b764e24a9?d=identicon&s=25 Marko Asplund (Guest)
on 2012-06-10 20:50
(Received via mailing list)
On Mon, Jun 4, 2012 at 11:45 AM, Yoko Harada <yokolet@gmail.com> 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
E184bc2347f90dd61b509de6eb43a8b6?d=identicon&s=25 Yoko Harada (Guest)
on 2012-06-12 08:47
(Received via mailing list)
On Mon, Jun 11, 2012 at 3:48 AM, Marko Asplund
<marko.asplund@ixonos.com> 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
D4c223beb610f1e5baa56a0b764e24a9?d=identicon&s=25 Marko Asplund (Guest)
on 2012-06-16 16:29
(Received via mailing list)
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
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.