Why in the world would you want to embed JRuby into your application instead of relying on a regular Ruby or JRuby installation? I can think of three reasons.
Note: this is a sister post to my description of the arguments needed to run JRuby via jruby-complete. Here I discuss the rationale for using JRuby like this.
What’s the upside?
You can bundle your Ruby runtime dependence into the application.
If you don’t know what I’m talking about here then you should probably stop reading right now. An old post by Err the blog summarizes the “vendor everything” principle quite well:
Quickly: fix it! Tell everyone to install the gem locally. Install the gem on your staging server. Carefully install the gem on your production server. Phew. Everyone’s got the same version, right? Right. Well, maybe. (At least the build works.)
I like vendoring the Ruby runtime for several reasons:
- I don’t want to ask my users to install anything outside of my application. I definitely don’t want to count on the end user having something installed. Depending on end users having a compatible version of Java is frustrating enough, let alone a JRuby installation. Depending on the JRuby installation can be annoying for developers as well. Take culerity as an example. You could spend a bunch of time screwing around with getting your system-wide JRuby installation just right. Or you could embed JRuby directly into culerity and be done with it.
- I don’t need to worry about version incompatibilities between the various runtimes. Incompatibilities can mean features I depend on are unavailable, subtly different, or outright broken. An interesting example of “subtly different” came up in an application I recently developed. At one point the sort implementation in JRuby changed from a stable sort to an unstable sort. As far as I know, Ruby doesn’t guarantee sort stability one way or another, so the change was ok from a Ruby perspective. Not so much for me. It turns out my application assumed a stable sort. Had I been dependent on the user’s Ruby installation, my application may have been using either the stable or unstable sort implementation, which was a variance it could not tolerate. (I’m glad I had automated integration tests that revealed this problem to me. I eventually concluded that the application’s behavior was fine with either the stable or unstable sort.)
- Using JarJar and a few tricks means you can distribute your Ruby application as a single jar file.
Your application may need to run in a constrained environment where you can’t install much, but Java is available.
A couple of years ago I started development on a new application for monitoring PeopleSoft services. Installing Ruby on the servers I was deploying to was not an option. Java was already there to support PeopleSoft. Thank goodness JRuby 1.0 had just been released.
Managing one file is easier than managing many files.
Copying around one jar file is easier than copying a directory with hundreds of files in it. Yeah, manipulating a directory isn’t always a pain, but the times where manipulating a big directory is a pain can be a really big pain.
What’s the downside?
Your application gets bigger.
jruby-complete is currently (as of version 1.4.0) sitting at around 11.5 megabytes. Do I care? Nope. This can be annoying but it generally doesn’t bother me. Especially when my application is already measured in tens of megabytes.
Figuring out and typing the correct commands to run your application isn’t trivial.
This part sucks. Running commands through jruby-complete is tedious when you don’t have any help from something like Rake tasks. The JVM boot time sucks as well. For these reasons I don’t recommend using jruby-complete for everything: when running small, one-off scripts, there’s just too much overhead. Thankfully, when I do depend on jruby-complete, I’m already working on an application where I’m using Rake to automate all kinds of things. So running lengthly
java commands isn’t a big deal because my Rake support is already there.
Thankfully, this companion post is chock full of tips for alleviating the pain from those nasty commands.