JRuby

From JVMLanguages


JRuby is an interpreter for the Ruby programming language written in Java. Although the semantics of Ruby and Java are very different, JRuby is quite good for integrating the two languages.

Table of contents

JRuby in the News

How to use JRuby

Invoking JRuby

JRuby includes a main class org.jruby.Main which can read a script off of the command-line arguments and invoke it. If no script is provided, JRuby will read the entire stream from standard input and then execute it. Unlike most other command-line interpreters, it does not evaluate it statement-by-statement.

   $ java org.jruby.Main
   print "the answer is: "
   a = 2 + 2
   print a.to_s, "\n"
   ^D
   the answer is: 4

If you provide a script, any arguments that follow the script will be appended to ARGV.

   $ cat print_sum.rb
   sum = 0
   ARGV.each { |x| sum += x }
   print sum.to_s, "\n"

   $ java org.jruby.Main print_sum.rb 2 2
   4

JRuby assumes the several Java system properties are set. This includes:

  • jruby.base
  • jruby.home
  • jruby.lib
  • jruby.shell
  • jruby.script

You can also invoke Ruby programmatically by obtaining an instance of org.jruby.Ruby.

   import org.jruby.*;

   public long doMath ()
   {
       Ruby ruby = Ruby.getDefaultInstance();
       ruby.defineReadonlyVariable("a", new RubyFixnum(ruby, 2));

       RubyFixnum out = (RubyFixnum)ruby.evalScript("a + 2");
       return out.getLongValue();
   }

Using Existing Ruby Libraries

JRuby is only distributed with its own Ruby libraries, which are used for integration with Java. The core Ruby libraries such as XXXX are not included and must be downloaded separately from a typical Ruby installation.

Interacting with Java Objects from Ruby

Java objects are represented inside of Ruby as an instance of the JavaObject class, which has methods that can be used to locate its Java class (JavaClass) and look up methods and fields via a reflection-like API.

However, in most cases there is no need to interact with JavaObjects directly -- JRuby can also create proxies around these JavaObjects that make them look like ordinary Ruby objects. This means that you can call methods on them directly. Calling a method on a Ruby proxy that returns another Java object will also automatically wrap that object in a proxy.

   public class MyJavaClass {
       public MyOtherJavaCLass a () {
           return new MyOtherJavaClass();
       }
   }

   public class MyOtherJavaClass {
       public int b () {
           return 42;
       }
   }

   class MyRubyClass
       def myMethod (myJavaObject)
           print "a.b = ", myJavaObject.a.b.to_s, "\n"
       end
   end

Ruby also supports proxies for Java classes, which expose static methods and constructors as if they were normal operations in Ruby. This is usually done through the include_package statement in Ruby, which creates proxies for all Java classes within that package.

The JavaBean standard dictates that nearly all Java objects have private fields and public accessor and mutator methods which named get* and set*, respectively. Ruby's coding style, on the other hand, generally leaves off the prefixes and instead uses the presence of a = suffix to indicate a mutator method. This convention is enforced by the language itself, which has syntactic sugar that makes a.b = 42; equal to a.b=(42);. Similarly, boolean accessor methods in Java are often prefixed with the word is, where boolean accessors in Ruby are conventionally suffixed with a question mark (?).

To ease the integration between Ruby and Java code, JRuby added support for mapping between these conventions and creating aliases on the Ruby proxies that follow the Ruby codingconventions. Thus the Java method Foo.getBar() can be called from Ruby either by foo.getBar() or by foo.bar. 2.4. Interacting with Ruby Objects from Java

Ruby has support for generating Java proxies from Ruby objects, however it is up to the caller to define the mapping between Java interfaces and Ruby classes.

BSF Support

The JRuby distribution contains a BSFEngine implementation called org.jruby.javasupport.bsf.JRubyEngine. However, the Languages.properties file included with BSF has this engine registered, so you will not need to register it explicitly. Simply use the language name ruby and the extension .rb.

Ruby's BSFEngine is responsible for converting all data types between Ruby's data types (RubyFixnum, RubyString, etc.) to Java's data types (Integer, Long, String, etc.). It does this conversion in both directions, for input parameters as well as return values.

Limitations

In the case of JRuby, we have a milestone against which we can measure its functionality. In fact, Ruby has a general conformance test called Rubicon that is designed to test all of the functionality that Ruby supports. According to the JRuby web site, 651 of the 933 (70%) Rubicon tests pass for 0.7.0. Is this still the most recent?

Articles