Need help with LOAD_PATH when embedding jruby

I am using the JRuby 1.1.2 release.

I’ve been working on getting JRuby working as an embedded interpreter
in a larger Java system that I’m working with (I’m the ruby guy, not
the Java guy). I’ve successfully adapted the RubyLauncher class
suggested in the wiki [1] for my own use. Testing has progressed to
the point where I can instantiate a ruby class and execute methods
within it. However, this only works if I instantiate the RubyLauncher
helper class with an absolute path that points to my ruby file on the
file system.

I need to package the ruby files up in the jar with everything else.
I’ve tried adding all of the paths within the jar using the #loadPaths
facility within the RubyLauncher helper, but no joy. As soon as I
remove the absolute path from my ‘new RubyLauncher()’ call, it can’t
find the ruby file. I get the following exception (visible in jdb).

Exception occurred: org.jruby.exceptions.RaiseException
(uncaught)“thread=SchedulingUnitThread|tid=1114683744|”,
org.jruby.evaluator.ASTInterpreter.rootNode(), line=1,656 bci=88

Here’s some code:

public class RubyLauncher {

private IRubyObject rootRubyObject;
private Ruby runtime;

/**
*

  • @param initialRequire The name of the .rb file that is your
    starting point (on your claspath).
  • @param rootRubyClass The name of the ruby class in the above .rb
    file, must have no-arg constructor (a new instance will be created).
    */
    public RubyLauncher(String initialRequire, String rootRubyClass) {
String bootstrap =
  "require \"" + initialRequire +  "\"\n"+
  "class Bootstrap \n" +
  "  def initialize  \n" +
  "    @object = " + rootRubyClass + ".new \n" +
  "  end \n" +
         "       def execute_no_params(method_name) \n" +
         "               @object.send(method_name) \n" +
         "       end \n" +
         "       def execute_with_param(method_name, param) \n" +
         "               @object.send(method_name, param) \n" +
         "       end \n" +
  "end \n" +
  "Bootstrap.new";


// This list holds the directories where the Ruby scripts can be

found.
List loadPaths = new ArrayList();
loadPaths.add(“com/audentestech/util/lib”); // add “lib” and others
as necessary
loadPaths.add(“com/audentestech/ruby/lib”); // add “lib” and others
as necessary
loadPaths.add(“/lib”); // add “lib” and others as necessary

runtime = JavaEmbedUtils.initialize( loadPaths );
RubyRuntimeAdapter evaler = JavaEmbedUtils.newRuntimeAdapter();
rootRubyObject = evaler.eval( runtime, bootstrap );

} // end of constructor method
}

Can any other folks who have successfully embedded JRuby give me a
hand? Thanks!

cr

[1] http://wiki.jruby.org/wiki/Direct_JRuby_Embedding


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Jun 2, 2008, at 10:44 AM, Chuck R. wrote:

I need to package the ruby files up in the jar with everything else.
I’ve tried adding all of the paths within the jar using the
#loadPaths facility within the RubyLauncher helper, but no joy. As
soon as I remove the absolute path from my ‘new RubyLauncher()’
call, it can’t find the ruby file. I get the following exception
(visible in jdb).

I got it working, but it doesn’t seem right. Here’s how I did it.

In the RubyLauncher constructor I added two calls to #loadPaths.add
and passed in the internal jar paths where I put my ruby files.

loadPaths.add(getPathToJar("/com/audentestech/util/lib/"));
loadPaths.add(getPathToJar("/lib/"));

Then I wrote a little utility function called #getPathToJar that does
just what it says. Here’s that code:

private String getPathToJar(String jar_internal_path)
{
java.net.URL url =
RubyLauncher.class.getResource(jar_internal_path);
return url.getPath();
}

Now the jruby runtime can find my ruby files.

Unless someone says this is wrong and I should be doing it another
way, I’ll add this to the wiki.

cr


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Chuck,
Good to know that you figured it out.

I had the same issue myself (needing to package all .rb inside a JAR).
Instead of adding each path manually, I took a different approach and
directly
hook into the require chain. Here is the code I use in my app. You may
find it
useful.

alias original_require require

def require_when_in_jar(path, *extra)

Rewrite ‘file:/app.jar!/sub/file.rb’ to ‘sub/file.rb’, for use in

JAR.
path = path.gsub(/^.*!//, ‘’)
original_require(path, *extra)
end

alias require require_when_in_jar

Because of the need to bundle files inside a JAR, we disallow any

overriding

of the require method. Otherwise, active_support/dependencies.rb would

be

able to override the method and bypass the path-rewrite.

def Object.method_added(name)
if :require == name && !(@@allow_override_require ||= false)
@@allow_override_require = true
alias require require_when_in_jar
@@allow_override_require = false
end
end

Peter

Chuck,
Can your way of adding to the load path be generalized to be dynamic,
so that it will load all the paths dynamically without having to
configure
each path explicitly? The one advantage that I see with hooking the
require
statement is that you can deal with any path inside a JAR, without
having to
add them explicitly.

I have met you a few times in the Chicago North side Ruby meetups. I
agree, it’s time for another time. Let me see what I can put up. :slight_smile:

Peter

On Jun 2, 2008, at 2:02 PM, Peter K Chan wrote:

end
end

Peter

Peter,

that’s another way to skin this cat! Your approach has the benefit of
being in ruby while mine was written in java. Honestly, I find the
java approach to be a bit cleaner in solving this problem. I updated
the wiki page to include my code along with a short explanation. I’d
be happy to add yours to the page as an alternate approach if you
think it’s worthwhile.

cr

PS - if you are the same Peter Chan in Chicago who goes to the
occasional north side ruby/rails gathering, it’s time to schedule
another one!


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

The more I think about this, the more convinced I become that it isn’t
necessary.

Instead of adding all of the paths in a jarfile to the LOAD_PATH,
there should be a convention that follows what gems do. Put a file at
the top level of the /lib directory that ‘requires’ all subfiles. This
convention would keep all of the ruby files in a single directory
hierarchy and be familiar to anyone who has built a gem or had to mess
with the guts of one.

An example would be like this:

sample directory layout

/lib
/lib/foo.rb
/lib/foo
/lib/foo/bar.rb
/lib/foo/baz.rb

contents of foo.rb

require ‘foo/bar’
require ‘foo/baz’

cr

On Jun 4, 2008, at 9:52 AM, Chuck R. wrote:

loadPaths.add(path);

jruby

and directly
original_require(path, *extra)
if :require == name && !(@@allow_override_require ||= false)
that’s another way to skin this cat! Your approach has the benefit of
another one!
To unsubscribe from this list, please visit:


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Yeah, it looks possible to generalize it so it adds all paths in the
jarfile. It’s a bit beyond my java capability right now but it would
be like this (pseudo-code):

jarfile = RubyLauncher.class.getResource(“/”).getJarFile();
for(JarEntry entry : jarfile.entries()) {
paths.add(entry.getAttribute(Name));
}
paths.removeDuplicates();
for(String path : paths) {
loadPaths.add(path);
}

Maybe it is easier to do it in ruby after all. :slight_smile:

If we have another north side meetup, post on the Chirb list and I’ll
see it.

cr

On Jun 4, 2008, at 12:58 AM, Peter K Chan wrote:

I have met you a few times in the Chicago North side Ruby meetups. I

hook into the require chain. Here is the code I use in my app. You
end
@@allow_override_require = true
being in ruby while mine was written in java. Honestly, I find the

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Chuck,

I went back and re-read your original message, and now I am not so sure
anymore if my response was appropriate to your question. JRuby does load
.rb
files from the classpath. So if you have a file
/home/user/app.jar/lib/src.rb,
you can load it by require ‘lib/src.rb’.

The reason I had to hook the require statement was because some of the
ruby
libraries used FILE to load their dependencies, and since FILE
contains the /home/usr/app.jar prefix, I had to remove that to get JRuby
to
load the files from the classpath. Otherwise, simple loads such as
require
‘lib/foo.rb’ should work as is. (at least, that’s what I now think I
did; the
code was from more than a year ago).

Assuming that you are not using libraries that tries to load their own
files,
I am a little confused by why you would have to fiddle with the load
path at
all. Perhaps the RaiseException that you mentioned in your original
email
contains information about that?

Peter