Making the Complex Usable with JRuby

Brian Sam-Bodden

One of the factors that made Java hugely successful is the myriad of open source libraries and frameworks. The successful ones have had now a decade or more to mature and grow. A side effect of being successful is both intended and unintended complexity. In the next few pages I will show you how a JRuby Domain Specific Language (DSL) can breed new life into an old powerhouse Java library.

In recent years it has become clear that the lasting legacy of Java is not Java “the language” but Java the platform and specially the open-source community that it has fostered over the last 15 years.

Many developers (including yours truly) experienced a great deal of success with the Java language but as the years went by it started to become apparent that the safety “features” of the language that made it so popular were getting in the way of progress. This became painfully clear in the area of Web Development and it became borderline embarrassing when we were introduced to the Ruby on Rails framework and witness the productivity boost that the combination of a dynamic language like Ruby and a DSL-based approach to a framework brought to the table.

Today, we recognize that the Java language is just another player in the world of the Java Virtual Machine. The JVM is an amazing and pervasive piece of software that in the early days of Java played second fiddle to the language. This is no more, everyone know acknowledges that this amazing, highly tuned, multiplatform computing engine dominates the present and permeates the future of computing.

As I write this article there are more than 200 language implementations available for the JVM, many of them now being used in the “enterprise” and not only in academia. I strongly believe that this decade marks the official beginning of the “polyglot” era of programming with the JVM smack in the center of this new world.

Ruby

Ruby is a dynamically typed language created by Yukihiro “Matz” Matsumoto. Ruby is a general purpose, multi-paradigm language inspired primarily by Smalltalk, Perl, Lisp and Eiffel.

As David Heinemeier Hansson puts it “Beauty leads to happiness, happiness leads to productivity, thus beauty leads to productivy”. If you have never worked with Ruby, after a few hours coding it will immediately hit you. Things just make sense! My first thought was “there is no way in hell this was build by committee!” Indeed it wasn’t. Matz set out to create a language for him to enjoy in which the main ideals were that programming should be fun and that the language should behave in predictable ways for those experienced with it core principles (this is often referred as the “Principle of Least Surprise”.

Rather than praise Ruby, let me show some quick examples the simplicity of Ruby. Say we have to do some basic, brain-dead file manipulation; load a text file and print its contents line by line. In Java we would do something along of the lines of:

After years of doing Java we have come to accept code like that shown in Listing BSB-1. I equate this code to wearing a deep-ocean, mesh-reinforced diving suit to go to the beach. If you go to the beach there is the possibility that you might go under, and that in the depths of the ocean a great white might come after you. Yes, it is possible but also highly improbable.

With Ruby we don’t even have to commit to create a permanent record of the operation performed in Listing BSB-1, we can get our work done directly in the Interactive Ruby Shell (IRB).

As seen in Listing BSB-2, Ruby provides a File class, which has an open method that takes the name of the file and a file mode (in this case ‘r’ for read-only). So far so good, next is where the Ruby Way kicks in! The result of the call to open returns a File which mixes-in the Enumerable module, which gives it an iterator via the each method. The each method expects a block, the code wrap in the “do” and “end”. We can think of a block as an anonymous function and one of their basic usages of a block is loop abstraction. As opposed to Java, with Ruby we don’t need to peer into the internals of what we are iterating over, instead we provide a function with a known interface to the owner of the collection we want to iterate over. The result is less code and better encapsulation!

But Ruby was designed by a programmer and is therefore for programmers. Methods that would make sense to be included in the core of the language usually are! Therefore it is no surprise that the File class also has a “readlines” method, which returns an array and what do you know! Ruby knows how to print an Array:

As a fairly accomplish Java developer I can tell you without reservation that Ruby is the most productive environment I’ve ever develop applications in.

JRuby

JRuby is pure Java implementation of Ruby that started in the early 2000s. JRuby aims to bring the beauty and simplicity of Ruby to the Java world and bring the Java ecosystem to the Ruby world. This means that you gain the best of both worlds; From a Java application you get to use Ruby applications and libraries and from a Ruby application you get access to Java Libraries (in a Ruby-eske way).

JRuby also runs significantly faster than most other Ruby implementations (if you don't count VM startup), it supports native threads, Unicode and can be fully compiled ahead of time or just in time.

JRuby also bridges the gap left by Java the language. Dave Thomas once described Java as “the safety scissor of the programming world”. Following that analogy, Ruby is then a samurai sword and via JRuby it brings powerful features to the Java world: Blocks, Closures, Open Classes, Meta-programming and Duck-typing all crucial ingredients when building a Domain Specific Language.

Calling Java From JRuby

In order to enable Java features in a Ruby program we need to add the ‘java’ module to our program. We can also include specific Java packages and group them under a Ruby module (modules are like un-instatiable, namespaced code containers; they can contain classes, methods, constants and free-flowing code)

We these powerful Java libraries in place we can now let Ruby loose and write some code to use the Java 3D API. The Ruby class ThreeDimensionalCube creates a rotating, multi-colored cube; the power of Java meets the ease of development of Ruby:

We run the example (note that there is no need for a main method) with the last two lines in Listing BSB-5. First we instantiate a ThreeDimensionalCube object and then call the show method on said object. The result is shown in Figure BSB-1.

Figure BSB-1

Our Problem Domain: Dealing with XML

One of the pain areas of Java development has always been dealing with XML. We could attribute this to the overuse (or is it abuse) of XML in the Java world. But if you were unlucky enough to deal with the SAX and DOM API in Java you probably don’t have any hair left by now.

I was in the same boat, until I discovered XOM (XML Object Model) is one of the most versatile Java XML libraries in existence. XOM is a Tree-based API like DOM and JDom and it aims for correctness, simplicity and performance. In the Java world XOM provided the best of both worlds, fast parsing and a tree-model that allows navigation of the XML documents.

Using XOM is easy to create well-formed XML documents, for example Listing BSB-6 shows a “Hello World” example available with the XOM distribution.

If you ever built or parsed XML with any other Java API (other than JDOM or dom4J) you would be able to appreciate what XOM can do for you.

Close but Not Cigar!

Although XOM does a great deal of heavy lifting for you, if you are Rubyist, Listings BSB-6 and BSB-7 feel like they reveal too much about how XOM works internally and hide the intent of the code with too much plumbing.

Ruby has an XML building library, created by Jim Weirich called XML Builder (or Builder for short). Builder is a Ruby DSL for constructing XML documents. For example, to recreate the “Hello World” example we could do write a simple Ruby program like that shown in Listing BSB-8

So what makes Builder a DSL? Note the call to the method “root”. As a Java developer your first reaction is “root must be a method of this builder object, right?” Wrong! Under the covers the call to the method root is being trap by a hook method called method_missing. Think of it as an event listener that is invoke in the event that an object is sent a message it cannot handle.

Internally, Builder is seeing that we are trying to invoke a non-existent method called “root” and instead adds an XML tag to the underlying document being created.

Builder is not as robust or correct when it comes to building XML when compared to XOM and it is nowhere near as fast. Builder, as clearly stated by its name, only “builds”.

Being the greedy developer that I am, I wanted the best of both worlds. How can I get Builder’s semantics for XML building mixed with the XOM’s ability to efficiently parse and navigate XML with XPath?

Excemel: A JRuby DSL for XML Manipulation

The answer to the previous question is a simple one: Use XOM but make it look like Builder. Enter Excemel! A simple JRuby DSL for XML manipulation. Excemel borrows Builder’s semantics for building an XML document backed by an underlying XOM model. Excemel also allows you to parse and manipulate an existing document and exposes XPath functionality in a simple way.

Let’s start with the simple Hello World example again, as shown in Listing BSB-9.

Listing GAN-10 demonstrates the invocation of the method in Listing GAN-9.

gsmEvent "stage", {
transitions from:"modified", to:"staged"
}

Listing BSB-11

Listing BSB-12 shows the full power of a JRuby DSL. Remember the RSS headline extractor example shipped with XOM? With Excemel we can bring intent back to the forefront of our code. In about 1/3 of code of the original XOM version Excemel can more clearly perform the same task (with the same efficiency and accuracy, it is XOM under the covers!)

Conclusion

I hope that this short walk through the world of JRuby will open your eyes to the power of mixing a powerful dynamic language with a robust, fast and battle-tested Java library. Dynamic languages on the VM are paving the way of the future. Groovy and Ruby via JRuby can help us improve the current state of Java and make programming fun again!