It’s also a benefit to the Ruby community at large, even if you don’t run it. The various Ruby implementations are all working together on RubySpec, a large test suite which is effectively defining the Ruby language and verifying that all the implementations are compatible.

Installation and running code

Installation really is as simple as promised by the web site. You download the archive, unzip it and add the bin directory to your PATH. Then you have a ruby compatible interpreter, jruby.

And after that, it “just works”. It behaves the same way as the standard ruby interpreter and, apart from a slightly longer startup time, performance is great.

Running jgem allows you to install gems, including Ruby on Rails. There is a slight limitation in that Ruby libraries with components written in C won’t work because they rely on the internals of the C ruby interpreter, but any pure-Ruby library will be fine. (note that you do need the bin directory in your PATH for jgem and the like to run, but jruby can be run using a full path to the interpreter)

JRuby isn’t quite pure Java itself. The distribution archive includes JNA to allow it access to the POSIXAPI for full compatibility with the C interpreter. This uses native code, and pre-compiled shared libraries are included in the distribution for various common OSes and architectures.

Ruby to Java integration

This is wonderful, because there are lots of useful Java libraries. If you want to do something, there’s probably a tried and tested solution available. Even better, Java libraries are very easy to install — just download the jar file and put it in the CLASS_PATH. If you’ve ever had fun installing third party libraries (perhaps you don’t run Linux?) then this is a breath of fresh air!

JRuby goes out of its way to allow the code to be written in a Ruby style or in Java style. JRuby uses Java reflection to work out the Java types then converts the Ruby objects accordingly. It sounds like a lot of magic, but it generally works very well.

The only case where it breaks down is when Java generics are involved. For example, if you have a Map<String,String>, you will get some very unexpected types being inserted into the map if you call put(). Because of the backwards-compatible way Java generics work, during compilation the types are erased and the JVM sees the Map<String,String> object as a plain Map. When JRuby uses reflection to determine the signature of the put method, it has no idea that the object is expecting a String and doesn’t convert the Ruby object appropriately. This can result in some entertaining debugging sessions.

Java integration means you can write code which uses all the Java libraries with a much nicer syntax than Java itself, but there is going to be a performance hit with all the type conversion. In this case, it’s probably worth writing a bit of Java code and call into that with a single method call from Ruby.

Java to Ruby integration

(This section applies to JRuby 1.3.1. As Charles Nutter (one of the JRuby developers) points out in the comments, there’s lots of work going on to make this easier in the next version.)

It’s obvious that the JRuby team expect you to start your programs using the jruby command, as calling Ruby from Java isn’t as pleasantly straightforward as the other way round. The wiki page on the subject isn’t as helpful as the equivalent for Ruby to Java, and most of the bits you need aren’t included in the standard JRuby distribution and have to be downloaded separately.

Two recommended methods are offered. The Java 6 scripting API looks the most promising, but I simply couldn’t get this to work. Investigations suggest that there aren’t the necessary entries in the manifest inside the relevant jar files to register the Ruby interpreter with the scripting API. I gave up on this one.

The other one is the Bean Scripting Framework, but it just seemed like yet more Java infrastructure to contend with. I have to confess I didn’t even try this one.

Finally, an alternative to the recommended methods is to call the JRuby APIs directly, which is discouraged because they may change over time. I doubt this is a huge problem since any new version of JRuby is going to require a good amount of testing and validation, and the interface between the two languages is quite small. And besides, there’s some useful methods defined in JavaEmbedUtils (found in a jar file which needs to be downloaded separately) which should be stable over time.

The wiki pages give a few pointers, but it took some experimentation to find a good way of integration. My eventual solution was a ‘boot’ script which required all the Ruby code and returned a Ruby object on which methods could be called by the Java. This avoids running eval all the time, which seems a bit of an inefficient way of calling Ruby methods.

After running this bootstrap code, interfaceObject is a Ruby object which can be called whenever required. To pass information to the boot script, constants are defined in the initial code passed to eval, in this example, CODE_ROOT is a directory name passed in by the Java code.

In this example, Response is a Java class I’ve defined to contain the result of the Ruby method. It’s created on the final line of the do_something method using the normal Ruby to Java integration.

To get this to run, you’ll need to work out the various options you need on the command line. The easiest way of working them out is to copy the jruby file, which is actually a long script, then replace the final exec which runs the java interpreter with an echo. Simply copy the arguments and adjust appropriately.

This sets the environment expected by JRuby, then runs the program from the oneis.jar file.

Should you write Java which calls Ruby?

You have to decide what language starts your program. Using Ruby is easier — just run the jruby interpreter and it’s very simple. Using Java is more complex, but perfectly possible and gives more flexibility.

I choose to have Java in control of the process, so I could write an application server which met my exact requirements. But it’s not the easiest route.

Which Ruby implementation should you use?

At the moment, it seems to be a choice between the standard C Ruby interpreter and JRuby. Both are being used for deploying large applications. I suspect the thought process looks something like:

Are your Ruby scripts short and run often? Use C Ruby.

Would using Java libraries be useful? Use JRuby.

Would real threading help your application make efficient use of resources? Use JRuby.

Do you depend on a Ruby library with a C component? Use C Ruby.

If you benchmark your app on JRuby, is it significantly faster? Use JRuby.

Is C Ruby annoyingly packaged on your platform? Use JRuby.

Otherwise use C Ruby.

For my purposes, JRuby is fantastic. Instead of having Java code running in a separate process and communicating with multiple Ruby application servers over sockets, I can move everything into a single, properly multi-threaded process with seamless Java and Ruby integration.