Nick Sieger: JRuby 1.1.6: Gems-in-a-jartag:blog.nicksieger.com,2005:TypoTypo2010-11-22T18:04:32+00:00Nickurn:uuid:9d08015d-55b9-4438-918d-4aa9902ad6942009-01-12T20:58:33+00:002010-11-22T18:04:32+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:002010-11-22T18:04:32+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:002010-11-22T18:04:33+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:002010-11-22T18:04:33+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:002010-12-21T22:34:49+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-gems 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-gems/bin</code>, <code>chronic-gems/cache</code>, <code>chronic-gems/gems</code>, and <code>chronic-gems/specifications</code> directories and installed <code>chronic</code> and its dependencies into it. Now, simply package those directories into a jar file. <strong>WARNING</strong>: make sure you don’t give the jar file name the same basename as the library or gem inside you wish to use (e.g., chronic.jar), because JRuby will load chronic.jar when you <code>require 'chronic'</code>!</p>
<div class="typocode"><pre><code class="typocode_default ">$ jar cf chronic-gems.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-gems.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-gems.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-gems.jar
$ java -jar jruby-complete-1.1.6.jar -rchronic-gems.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>
<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>