From the same "good + good == doublegood" mindset that brought us peanut butter and chocolate (together at last, as God intended) -- JRuby binds Ruby and Java together in an east meets west, loose type meets strictly typed world that we shall peer into.

JRuby is a 100 percent Java implementation of the Ruby interpreter, and while it does not have all the features of Ruby it does have most of built-in classes of the language.

Needless to say that in order to make best use of JRuby, you should have an understanding of Java and Ruby. If you are a Java programmer, check out our introductory articles to Ruby as this will be the limit of what we shall explore in this article.

Getting JRuby

First thing to do is head over to http://dist.codehaus.org/jruby/ and grab the latest jruby-bin archive, it contains everything we need. Simply extract it to a place of your choosing and add your-jruby-dir/bin to your path variable.

You should be able to execute the following now:

jruby -v
ruby 1.8.5 (2007-08-23 rev 4201) [ppc-jruby1.0.1]

On with the code

To begin with we will be using the interactive console that is invoked using the command:

jirb
irb(main):001:0> 

JRuby being a Ruby interpreter means that we can run any of the Ruby code we've seen previously.

irb(main):001:0> puts "Hello World"
Hello World
=> nil
irb(main):002:0> [1, 2, 3, 4, 5].each { |n| puts n*n }
1
4
9
16
25
=> [1, 2, 3, 4, 5]

No surprises there, but the real reason we are using this over the native Ruby interpreter is to make use of Java, so let's bring the Java framework in:

irb(main):003:0> require 'java'
=> true

However attempting to use some standard Java code will fail:

irb(main):004:0> System.out.println("Hello world")
NameError: uninitialized constant System
        from (irb):4:in `binding'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:150:in `eval_input'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:70:in `signal_status'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:147:in `eval_input'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:70:in `each_top_level_statement'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:146:in `loop'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:146:in `catch'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:146:in `eval_input'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:70:in `start'
        from :1:in `catch'
        from /Users/chris.duckett/tmp/jruby/jruby-1.0.1/lib/ruby/1.8/irb.rb:69:in `start'
        from :1

We are going to need to dig far back into the things that are taken for granted within Java to get the standard Hello World statement going.

A visit to an API page that you would not have seen for a long time reveals the solution. System is actually a member of the java.lang package and out is a field on System with println being a method on out.

That means that in order to call it properly we need to do this:

irb(main):005:0> java.lang.System::out.println("Hello World")
Hello World
=> nil

just to keep it interesting, the following also works:

irb(main):005:0> java.lang.System.out.println("Hello World")
Hello World
=> nil

and just to prove that we can have Ruby and Java on the same line

irb(main):006:0>  puts java.lang.System::err.println("Hello World")
Hello World
nil
=> nil

Up to this point we have been using the Java way of giving parameters, but thanks to Ruby we can dismiss the parenthesis.

irb(main):007:0> java.lang.System::out.println "Hello World"       
Hello World
=> nil

Another of the benefits of JRuby is that it allows easy introspection on objects, you may never use the Java reflection API again.

To see all the methods, we simply call the methods function on the object as we would in Ruby

irb(main):008:0> java.lang.Math.methods
=> ["log", "abs", "cosh", "round", "tanh", "IEEEremainder", "max", "log1p", "sqrt", "rint", "pow", "atan", "min", "to_radians", "asin", "expm1", "ulp", "acos", "signum", "sin", "tan", "to_degrees", "toRadians", "floor", "atan2", "ieeeremainder", "ceil", "exp", "cbrt", "hypot", "cos", "log10", "toDegrees", "sinh", "random", "inherited", "new_proxy", "new", "java_class", "singleton_class", "java_class=", "to_java_object", "[]", "new_instance_for", "superclass", "initialize_copy", "allocate", ">", "autoload", "private_instance_methods", "const_defined?", "instance_method", "const_get", "<=>", "<", "include?", "public_class_method", "module_eval", "protected_method_defined?", "included_modules", "constants", "private_class_method", "protected_instance_methods", "class_eval", "trap", "included", "extended", "autoload?", "const_missing", "to_s", "class_variables", "ancestors", "<=", "const_set", "name", "private_method_defined?", "===", "public_instance_methods", "public_method_defined?", "instance_methods", ">=", "method_defined?", "java_kind_of?", "include_class", "object_id", "frozen?", "eql?", "=~", "methods", "to_a", "tainted?", "javax", "taint", "public_methods", "dup", "method", "==", "singleton_methods", "is_a?", "instance_eval", "equal?", "instance_variable_get", "com", "instance_of?", "hash", "inspect", "java", "org", "__id__", "clone", "__send__", "id", "instance_variable_set", "send", "untaint", "class", "protected_methods", "kind_of?", "instance_variables", "display", "extend", "freeze", "private_methods", "nil?", "type", "instance_exec", "respond_to?"]

Similiarly we can find out the constants as well:

irb(main):009:0> java.lang.Math.constants                          
=> ["PI", "E"]

View the ancestors of a class:

irb(main):011:0> java.lang.Math.ancestors
=> [Java::JavaLang::Math, Java::JavaLang::Object, ConcreteJavaProxy, JavaProxy, JavaProxyMethods, Object, Kernel]

and even the class type:


irb(main):012:0> java.lang.Math.class    
=> Class
irb(main):013:0> java.lang.class     
=> Module

Typing out full package names gets tedious, so you can use the include_class function to import a class.

irb(main):015:0> include_class java.lang.System
=> Java::JavaLang::System

You can then use the class in the same way as though you had used an import statement in Java:

irb(main):016:0> System.out.println("We've been imported")
We've been imported
=> nil

Including a class will fail though if you try to load a class that exists in the Ruby namespace already:

irb(main):014:0> include_class java.lang.Math
(eval):1 warning: already initialized constant Math
=> Java::JavaLang::Math

The way to get around this is to rename the class, in this instance the Math class becomes JMath:

irb(main):017:0> include_class('java.lang.Math') {|package,name| "J#{name}"}
=> ["java.lang.Math"]

and we can use it like so:

irb(main):018:0> JMath::PI
=> 3.141592653589793
irb(main):019:0> JMath.class
=> Class
irb(main):020:0> JMath.ancestors
=> [Java::JavaLang::Math, Java::JavaLang::Object, ConcreteJavaProxy, JavaProxy, JavaProxyMethods, Object, Kernel]

Interpreting Java This was published in Interpreting Java, check every Tuesday for more stories

Related links

Comments

1

Gavri Fernandez - 08/11/07

"just to keep it interesting, the following also works:"

That it does isn't specific to JRuby. I'm not saying that you're saying it is. But it's kind of misleading.
:: and . are different only by convention. You can use :: to access instance methods and . to access class constants, if you want to.

» Report offensive content

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

1

Gavri Fernandez - 11/08/07

"just to keep it interesting, the following also works:" That it does isn't specific to JRuby. I'm not saying that you're saying ... more

Log in


Sign up | Forgot your password?

  • Staff XP stays on life support for longer

    This week's Roundup looks at Microsoft's decision to extend the life of Windows XP, the release of Microsoft Surface SDK, Firefox's new Geode plug-in, Yahoo's new tool -- Smush It and more. Read more »

    -- posted by Staff

  • Chris Duckett The good and truly awful celluloid depictions of computers

    Ever wonder why your lawyer uncle leaves the room whenever you turn over to Boston Legal? Or why your forensic science cousin can't stand crime drama? You know the answer: it’s the horrid trivialisation and dumbing down of an occupation to make it appear entertaining. Sometimes it is so unbelievable that it actually hurts and yelling at the screen is the only outlet. Read more »

    -- posted by Chris Duckett

  • Brendon Chase Apple's iPhone engineers to tour Sydney, Melbourne

    Aussie developers will be able to get up close and personal with some of the iPhone engineers in November to learn how to build applications for the platform. Read more »

    -- posted by Brendon Chase

What's on?