Nick Sieger: JRuby 1.1.6: Gems-in-a-jartag:blog.nicksieger.com,2005:TypoTypo2009-01-12T20:58:33+00:00Nickurn:uuid:9d08015d-55b9-4438-918d-4aa9902ad6942009-01-12T20:58:33+00:002009-01-12T20:58:33+00:00Comment on JRuby 1.1.6: Gems-in-a-jar by Nick<p>Jay: I haven’t personally tried running a lot of gems out of a jar file yet. JRuby is not yet fully consistent with all its file APIs in knowing how to manipulate file:// urls. For example, the common practice of <code>require File.dirname(__FILE__) + '/../relpath'</code> is probably not going to work. If you try stuff, please file bugs!</p>
<p>As for deploying Adhearsion apps in an .ear, that probably deserves a larger discussion in #jruby. You need to tell me what kind of services and interfaces Adhearsion needs and provides, and we can figure out whether it should be in an .ear, a .war, or possibly just a standalone application (something like the last example).</p>Jay Phillipsurn:uuid:df97c658-57ec-4cfa-9cf8-f5b5c0bc0c072009-01-11T18:59:39+00:002009-01-11T18:59:39+00:00Comment on JRuby 1.1.6: Gems-in-a-jar by Jay Phillips<p>This is awesome, Nick! A few questions:</p>
<ul>
<li>How well does ActiveRecord play when running in a .jar? I heard that the ActiveRecord’s model reloading logic broke down at one point due to the JAR filesystem using URIs for its files.</li>
<li>How different is the .ear format from .jar and...</li>
<li>...does this now mean I can deploy Adhearsion apps as an .ear file into a JEE container? :)</li>
</ul>Andy Shenurn:uuid:8931bd77-3352-411e-adc2-760a273395422009-01-11T08:49:36+00:002009-01-11T08:49:36+00:00Comment on JRuby 1.1.6: Gems-in-a-jar by Andy Shen<p>I started to try to make use of activerecord’s schema migration in Java projects . Before this post I had to require users to set GEM_PATH but now I modified the jruby-complete jar as you suggested and that should make deploying the tool much easier :)</p>
<p>Thanks Nick.</p>James Britturn:uuid:7e590af2-bd44-4fda-b015-22e1b490654e2009-01-10T22:16:13+00:002009-01-10T22:16:13+00:00Comment on JRuby 1.1.6: Gems-in-a-jar by James Britt<p>This seriously rules. Thanks!</p>Nick Siegerurn:uuid:924637a6-a799-47c7-be6c-986b51b864022009-01-10T20:04:00+00:002009-01-10T20:09:01+00:00JRuby 1.1.6: Gems-in-a-jar<p>As a result of some fruitful hacking at RubyConf 2008, I was able to modify JRuby so that gems can be loaded and used without having to unpack them. The feature became generally available with the <a href="http://docs.codehaus.org/display/JRUBY/2008/12/17/JRuby+1.1.6+Released">1.1.6 release last month</a>. Gems in a jar!</p>
<p><a href="http://flickr.com/photos/splorp/36991739/" title="Gem Jar">
<img src="http://farm1.static.flickr.com/26/36991739_48ab6e8fb7.jpg" alt="gemjar"/>
</a></p>
<div style="clear:both"></div>
<p><span style="font-size:75%">by <a href="http://flickr.com/photos/splorp">splorp on flickr</a></span></p>
<p>This opens up a couple new possibilities for running, packaging and deploying JRuby-based applications. Here are some ideas:</p>
<h2>Run Gem-based applications with <code>jruby-complete.jar</code></h2>
<p>JRuby has <a href="http://jira.codehaus.org/browse/JRUBY-969">bundled Rake and RSpec since version 1.0</a>. As of JRuby 1.1.6 the versions we bundle are Rake 0.8.3 and RSpec 1.1.11. With <a href="http://repository.codehaus.org/org/jruby/jruby-complete/1.1.6/jruby-complete-1.1.6.jar"><code>jruby-complete-1.1.6.jar</code></a> you can easily run these with <code>java -jar</code>:</p>
<div class="typocode"><pre><code class="typocode_default ">$ java -jar jruby-complete-1.1.6.jar -S rake --help
rake [-f rakefile] {options} targets...
Options are ...
$ java -jar jruby-complete-1.1.6.jar -S spec --help
Usage: spec (FILE|DIRECTORY|GLOB)+ [options]
-p, --pattern [PATTERN] ...</code></pre></div>
<h2>Package gem collections into reusable jar files</h2>
<p>One of the features I added was to enhance RubyGems to search for directories named <code>specifications</code> on the classpath and add them to the <code>Gem.path</code> automatically. This means you can package up a whole gem repository into a jar file for easy reuse and sharing of commonly used gems. There isn’t a tool for this yet, but the process is pretty straightforward. (If someone plays with this and can come up with a patch to build this into JRuby, we’ll gladly accept one.)</p>
<p>First, create a gem repository by installing the gems you want into it. Let’s say you want to package the natural language date/time parser <code>chronic</code>:</p>
<div class="typocode"><pre><code class="typocode_default ">$ java -jar jruby-complete-1.1.6.jar -S gem install -i ./chronic chronic --no-rdoc --no-ri
Successfully installed rubyforge-1.0.2
Successfully installed rake-0.8.3
Successfully installed hoe-1.8.2
Successfully installed chronic-0.2.3
4 gems installed</code></pre></div>
<p>With this command, RubyGems created <code>chronic/bin</code>, <code>chronic/cache</code>, <code>chronic/gems</code>, and <code>chronic/specifications</code> directories and installed <code>chronic</code> and its dependencies into it. Now, simply package those directories into a jar file:</p>
<div class="typocode"><pre><code class="typocode_default ">$ jar cf chronic.jar -C chronic .</code></pre></div>
<p>When you inspect the contents of the jar, you’ll see the gem repository structure in the root of the jar file:</p>
<div class="typocode"><pre><code class="typocode_default ">$ jar tf chronic.jar | head
META-INF/
META-INF/MANIFEST.MF
bin/
bin/rake
bin/rubyforge
bin/sow
cache/
cache/chronic-0.2.3.gem
cache/hoe-1.8.2.gem
cache/rake-0.8.3.gem</code></pre></div>
<p>Chronic is now a re-useable jar library that can be easily loaded, either by requiring the jar in ruby code or adding to the classpath:</p>
<div class="typocode"><pre><code class="typocode_default ">$ # Without chronic.jar
$ java -jar jruby-complete-1.1.6.jar -S gem list
*** LOCAL GEMS ***
rake (0.8.3)
rspec (1.1.11)
sources (0.0.1)
$ # With chronic.jar
$ java -jar jruby-complete-1.1.6.jar -rchronic.jar -S gem list
*** LOCAL GEMS ***
chronic (0.2.3)
hoe (1.8.2)
rake (0.8.3)
rspec (1.1.11)
rubyforge (1.0.2)
sources (0.0.1)</code></pre></div>
<p><strong>Note</strong>: Unfortunately this technique does not yet work with gems that include Java code in embedded jar files (e.g., hpricot, mongrel, jruby-openssl). See <a href="http://jira.codehaus.org/browse/JRUBY-3299">JRUBY-3299</a>. (We’d like to get this fixed for 1.1.7, but could use your help.)</p>
<h2>Bundle pure-Ruby gem applications into an uber-jar</h2>
<p>Taking a cue from the previous techniques, we can stuff the gem directories into a copy of <code>jruby-complete-1.1.6.jar</code> rather than creating a new jar, and distribute an entire gem-based application in a single file. Imagine something like:</p>
<div class="typocode"><pre><code class="typocode_default ">$ java -jar jruby-complete-1.1.6.jar -S gem install -i ./mycoolapp mycoolapp
$ jar uf jruby-complete-1.1.6.jar -C mycoolapp .
$ mv jruby-complete-1.1.6.jar mycoolapp.jar
$ java -jar mycoolapp.jar -S mycoolapp</code></pre></div>
<p>Bonus points to the enterprising individual who provides a patch to make this a one-step process, including creating a mechanism to provide a default <code>-S</code> script so that <code>java -jar mycoolapp</code> is all that’s needed to run the application.</p>
<p>I hope you find interesting uses for this new feature. Let us know what you make with it!</p>