Wednesday, February 1, 2012

Bundling Gems in Jars/Wars for Jruby

As part of Virgil's ability to deploy ruby scripts to a remote Hadoop cluster, we needed to package gems' into that Hadoop jar.  After a bit of monkeying around, we got it.

This is the key piece of information:
"Because the operation of Java's classpath and Ruby's load path are so similar, especially under JRuby, they are unified in JRuby 1.1. This results in a number of unified capabilities:...

  • Everything in the Java classpath is considered to be a load path entry, so .rb scripts, for example, contained in JAR files, are loadable."
First thing you need is to actually get your hands on the gem.  To do this, you can run jruby to grab the gem.

java -jar jruby-complete-1.6.0.jar -S gem install -i rest-client rest-client --no-rdoc --no-ri


This will fetch the gems and install them into the current directory under the directory "rest-client".  In that subdirectory you'll find: bin, cache, doc, gems and specifications.  The actual code for the gems is found in the gems directory.  In the case of rest-client, you'll find two directories that contain the code: mime-types-1.17.2 and rest-client-1.6.7.

This is what you need to bundle into the jar.  We copied those two directories into our java project under src/main/resources/gems/.

One approach would be to simply include those directories on your classpath.  Another approach is to programmatically adjust the loadpath to include those directories.   You can do this with the following lines:

List paths = new ArrayList(); 
paths.add("gems/rest-client-1.6.7/lib/"); 
paths.add("gems/mime-types-1.17.2/lib/"); 
this.rubyContainer = new ScriptingContainer(LocalContextScope.CONCURRENT); this.rubyContainer.setLoadPaths(paths);

Then, when using this.rubyContainer you'll be able to run ruby files that require the rest-client.

Since the ruby scripts are actually loaded via the classpath (from the loadpath), jruby is happy loading them from within a jar.  In our case, we built the jar using maven and the gems were included in the jar because we put them under src/main/resources/gems.

Its that easy.  Happy rubying.

No comments: