Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Why you should tap into the power of Ruby from the comfort of the JVM


For me, mid-2000 was the big bang of a new generation of languages that run on the JVM. Among the first languages interested in enjoying the benefits of the brilliant engineering behind the JVM were Scala, Groovy and Clojure. Both of them are still going strong and flourishing. But after them new languages have been created such as Golo, Ceylon, Kotlin and others.

As the popularity of languages based on the JVM constantly has grown, the JSR 223 specification was developed and shipped in Java 6. This specification allows Java developers to run languages not originally developed for the JVM within a Java program and on the same JVM. Thanks to this specification, languages like Python (using Jython), JavaScript (using Rhino on Java 6/7 and Nashorn on Java 8) and Ruby (using JRuby) can be executed from Java. How amazing is that?

In this post, I want to discuss how you can tap into Ruby from the JVM developer perspective and how well they integrate with each other. For this effort, I’ve decided to describe my experience integrating Asciidoctor into the JVM through a Java API.

Ruby is elegant compared to the Java perspective

“[Ruby is] a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.”

-Official Ruby Site (

In my opinion, one of the most interesting features of the Ruby language is that it feels natural to programmers. Any developer can read Ruby code without knowledge of the language and understand what the program is doing. But there are other objective features of Ruby that Java developers may find interesting. From the top of my head:

  • Easy POJO development
  • Development of a Domain-Specific Language (DSL)
  • Real Closures
  • Method missing handler
  • There are more than 10000 gems to be used like tilt, slim, haml, sass and, of course, rails

Let’s see some examples of Ruby code to convince you about the readiness of the language.

Example of a POJO in Ruby

class Node // <1>
  attr_reader :parent, :document, :context // <2>
  attr :id, :attributes // <2>

  def initialize context, opts = {} // <3> <4>
    if (@context = context) == :document
      @parent = nil
      @document = self
      if (@parent = opts[:parent])
        @document = @parent.document
    @attributes = (opts[:attributes] || {}).dup // <5>

  def parent= parent
    @document = (@parent = parent).document

  def role_equals? name
    name == @attributes['role']

  alias :role_is? :role_equals? // <6>

  def has_role? name = nil
    if name // <7>
      if (value = @attributes['role'])
        value.include?(' ') ? value.split(' ').include?(name) : value == name
        false // <8>
      @attributes.key? 'role'

class Block < Node
  attr_reader :content_model
  attr :blocks

  include ::Enumerable // <9>

  def initialize context, opts = {}
    @content_model = opts[:content_model] || resolve_content_model
    @blocks = []

  def block_node?

  def blocks?

  def << block // <10>
    block.parent = self
    @blocks << block

  def each &closure // <11>

  def resolve_content_model

  def to_s // <12>
    %(#{super.chop}{context: #{@context.inspect}, content_model: #{@content_model.inspect}, blocks: #{@blocks.size}}>)

doc = :document
para = :paragraph, content_model: :simple, attributes: {'role' => 'lead'}
doc << para
puts doc.first
puts doc.first.role_is? 'lead'
puts para.attributes.inspect
require 'pp'
pp doc //<13>


  1. Basic class definition.
  2. attr creates getter/setter methods automatically over defined attributes. attr_reader generates only the getters.
  3. initialize method is called when object is created.
  4. optional method arguments.
  5. || operator can be used as value check. If value is nil then the right expression value is returned.
  6. method aliasing.
  7. optional brackets in multiple places.
  8. return is not mandatory, implicit method return value of the latest sentence.
  9. Ruby does not support multi-inheritance directly. However it provides a facility called a mixin. Mixins give you a wonderfully controlled way of adding functionality to classes.
  10. you can do operators overloading. For example array operator (<<).
  11. passing closure to method.
  12. overriding to_s is used as string interpolation of objects.
  13. pretty-printer for Ruby objects.

Example of closures

def foo(bar, &block) // <1>
  callback = block // <2>

foo(5) {|x| x * x} # => 25 // <3>


  1. A closure is defined as latest parameter of a method and with & operand
  2. Call method is used to execute the closure with required parameters
  3. A closure can be implemented using brackets after method invocation

And a lot of DSLs are implemented using Ruby; Puppet and Vagrant are two examples that spring to mind. Here is an example of Asciidoctor DSL to register extensions:

require 'asciidoctor'
require 'asciidoctor/extensions'

# Used to process the following AsciiDoc content:
# [shout,10]
# Let's do this.
Asciidoctor::Extensions.register {
  block {
    named :shout
    on_context :paragraph
    parse_content_as :simple
    name_attributes 'vol'
    process &-> (parent, reader, attrs) {
      volume = ((attrs.delete 'vol') || 1).to_i
      create_paragraph parent, ( {|l|
          l.upcase.gsub /\.(?= |$)/, '!' * volume }), attrs

It’s worth it to spend a little time on the Ruby website and learn a little more about this language, it’s history and what makes it different.

JRuby: Where Ruby meets Java

So what is the the relationship between Ruby and JRuby?

The default Ruby interpreter is written in C. JRuby is an implementation of Ruby but written in Java. This means that any program written in Ruby is run in Java. So effectively, you can run any Ruby program without noticing that in reality is being executed inside the JVM. And the good news is that according to MRI performance using JIT & AOT, Ruby runs faster on the JVM!

But the most important piece of JRuby for Java developers is one known as JRuby Embed (aka RedBridge).

RedBridge is an small part of JRuby used to embed Ruby code atop a Java program. You can use it using a bare metal API, which means that you use internal classes provided by RedBridge to execute Ruby code inside Java; alternatively, you can you can use the JSR 223 spec as well. The disadvantage of the latest approach is that it raises the level of abstraction and probably you will end up by mixing both approaches, so for these examples we are going to use the JRuby Embed API directly.

Running Ruby inside Java

To start using JRuby, the first thing we must do is add jruby-complete.jar as dependency. We are going to use Maven approach but it would be similar with Gradle.

The main Java class for executing Ruby code inside Java code is the ScriptingContainer class. This class contains a set of methods to execute Ruby scripts. Here is the pom.xml:



import org.jruby.embed.ScriptingContainer;
ScriptingContainer container = new ScriptingContainer(); // <1>
container.runScriptlet("puts 'Hello from Ruby!'"); // <2> <3>


  1. Base class to execute Ruby scripts.
  2. Executes a simple Ruby line.
  3. `Hello from Ruby!` is printed to standard console.

Returning Data from Ruby

ScriptingContainer container = new ScriptingContainer();
container.put("message", "Hello from Java with help from Ruby!"); // <1>
IRubyObject result = container.runScriptlet("message.upcase"); // <2> <3>
System.out.println(result); // <4>

  1. A variable with the name message is set as String type and given value. JRuby will convert Java String to Ruby String automatically.
  2. Upcase method from message variable is called
  3. This script returns the passed _String_ but in upper case.
  4. `HELLO FROM JAVA WITH HELP FROM RUBY!` is printed to standard console.

This example is pretty simple, but what happens when RubyObject is not a “native” object but a complex object, like the Person class provided in previous example?

With JRuby you can proxy any IRubyObject into Java interface. Then for each call of Java method it passes the intent to execute the method with given name and set of arguments to Ruby. Then Ruby “sends” that message to backend object and if signature meets the contract then the method is executed and if not an exception of not found method is thrown.

Ruby call from Java interface

public interface Person {
  String getFirst();
  String getLast();
  boolean hasOverweight();

ScriptingContainer container = new ScriptingContainer();
Ruby runtime = container.getProvider().getRuntime();

String script = " 170cm, weight: 72, last: 'Doe', first: 'John')"; // <1>
IRubyObject result = (IRubyObject) container.runScriptlet(script);
Person person = JavaEmbedUtils.rubyToJava(runtime, result, Person.class); // <2> <3>
System.out.println(person.hasOverweight();); // <4>


  1. A person is created with a Ruby script.
  2. JavaEmbedUtils class is used to transform a Ruby object to Java.
  3. To Java type is set as third argument. In this case Person.
  4. hasOverweight method is called from Java as any Java method.

If you look closely to Java interface you see that methods defined are not exactly the ones created in the Ruby object. One of the great features of RedBridge is that it can convert Ruby naming conventions to Java conventions automatically. So although you can use Ruby naming conventions inside the Java interface, the best practice is to use Ruby conventions for Ruby code and Java conventions for Java.

As summary of conversions:

x.something -> x.getSomething()
x.something = 42 -> x.setSomething(42)
x.something? -> x.isSomething()
x.method_name -> x.methodName()

I really love the analogy by Dan Allen, who says that these interfaces are a wolf in sheep’s clothing: The Java interface is merely a skin worn so that it can walk among and interact with other Java objects. However, underneath, it is really still the true beast that it is. The skin gives it access.


Duck Typing and Java

“When I see a bird that walks like a duck and swims like a duck and quacks like a duck. Then I call it a duck.”
— James Whitcomb

The classic definition of what is duck typing by James Whitcomb says that duck typing is a style of calling methods where developers are only concerned with ensuring that object’s method follows the given contract (name and parameters) rather than belonging to a specific type.

This style is used in almost all dynamically-typed languages where the type itself is not as important as its behaviour.

Here is a simple example of duck-typing usage:

class Duck

  def quack // <1>
    return 'Quack'


class Bird

  def quack
    return 'Quack'


class Farm

  def sound(a) // <2>
    puts a.quack //<3>



  1. A method quack with no-args and returning a string is defined in both objects.
  2. Method sound requires one argument, but notice that you don’t specify which type.
  3. From the point of view of a var, it is only required that the object respond to the no-args (or optional args) quack method.

As notice above because Ruby is a not-strong language, it implements duck typing. And this fact means that as Java user I can pass classes that are implemented in pure Java as Ruby arguments if they meet the contract defined in Ruby part.

Let’s see the previous example of implementing animals in Java:

public abstract class Animal { // <1>
  public abstract String quack();
  public abstract String croak(); // <2>

public interface Farm { // <3>
  void sound(Animal a); // <4>

// code to get a new proxy of Farm object.
Farm f = ...
f.sound(new Animal() {
  }); // <5>

  1. An Animal abstract class is created. Because Java is strong typed, it is a good practice to rely on parent common object rather than java.lang.Object although it would be totally valid.
  2. Notice that we have defined a none existing method called croak. If it is called Ruby won’t find that method inside Animal Ruby object and NoMethodError: undefined method `croak` will be thrown.
  3. Farm interface to be proxied against Ruby object instance.
  4. It defines sound with Animal type. This method would work with java.lang.Object as well, but then as developer you must ensure that the passed object contains a method following quack signature.
  5. Extending from Animal ensures that developer implements quack method.

As shown in the previous example, duck typing is a pure expression of polyglot programming. Code is mixed between Java and Ruby, taking the full advantage of both worlds.


What are RubyGems (aka gems)? Gems are the standard format for distributing Ruby code. They are pretty much the same as jar files. Inside a gem you may find different files and directories, like program itself, libraries required, tests, executable script or metainformation files.

Almost all gems are published in a remote repository called It is exactly the same concept as Maven’s central repository, but for publishing gems.

Gems can be imported inside another project as library, so it can reuse the operations provided by the gem. While in Java we have a classpath, in Ruby there exists the same concept and it is called loadpath.

Any gem inside loadpath can be loaded inside Ruby code using required keyword.

LoadPath Classpath unification

It may seem a problem to have two spaces where objects are got. Java objects are loaded from classpath and Ruby objects from loadpath.

JRuby unifies these spaces so as a developer you can work with only one.

JRuby defines next three rules:

  1. Everything in loadpath is a classpath entry.
  2. Everything in classpath is a loadpath entry.
  3. Java Structures (jar) can be loadpath entry.

Notice that because of the second rule, you can copy any gem inside the classpath following the gem directory layout and it will be available to be loaded within the JVM.

Here is how you call a bundled gem:

container.runScriptlet("require 'asciidoctor'") // <1>
// From this point asciidoctor can be called in Java

Packaging gems inside jar

We have seen that gems can be stored inside any classpath element, directly within classpath as Java classes or in jar files. Of course each gem can be packaged in its own jar, multiple gems can be combined into a single jar or a mixed approach.

To work with them you have different approaches but the best way is to resolve gem dependency as any other jar dependency. Probably in your projects you will be using Maven as dependency management for your jars. The good news is that you can even add gems using Maven coordinates and thanks of gem-maven-plugin gems will be downloaded from and copied into configured directory. Here is the pom.xml:

    <gemHome>${}/classes</gemHome> <!-- 1 -->
      <phase>generate-sources</phase> <!-- 2 -->

    <groupId>rubygems</groupId> <!-- 3 -->
    <artifactId>asciidoctor</artifactId> <!-- 4 -->
    <type>gem</type> <!-- 5 -->
    <scope>provided</scope> <!-- 6 -->


  1. gemHome and gemPath are set to root of classpath. In case of Maven is inside classes folder
  2. Execution of plugin is linked to generate-sources Maven phase. When this phase is executed, defined gems are downloaded and extracted into classes folder
  3. To define a gem as dependency groupId should be set to rubygems
  4. artifactId is used to set the gem name. In this case asciidoctor gem and all its dependendencies are downloaded
  5. type is set to gem
  6. Because gems are downloaded directly as source code and not as package, provided scope is used

And Gradle users can use similar approach by using jruby-gradle-plugin. You can checkout a Gradle example at

Final Notes

In this post we have seen basic concepts of Ruby and a getting started guide for integrating a Ruby gem inside Java program. Now you should be able to develop Ruby code which will be consumed by Java program. So we can consider in this case that Java is the primarily language taking advantage of Ruby.

Of course JRuby also offers the integration in the other way. This means that your primary language can be Ruby, and taking advantage of Java. But this would require another post.

I think that one of the big advantage of JRuby is that you can run any Ruby code without having to install Ruby runtime in your computer. Only setting JRuby dependency on your project, and you will be ready to run Ruby code without any external tool or manual installation.

AsciidoctorJ is a really good example of this integration between Java and Ruby world. AsciidoctorJ is a Java library that integrates Asciidoctor into Java world. Since the beginning has been downloaded thousands of times and has been used as a base integration for different languages like Groovy and Scala.

Ruby, Strings and Symbols

Last note about Ruby. Ruby has two types of string: Mutable strings and immutable strings.

Mutable strings are strings that can be changed at runtime. It is the default string type in Ruby and are created by setting string value between quote (‘) and double quote (“). In Java there is no mutable strings type.

Immutable strings are strings that cannot be changed at runtime, but a new instance is created every time is manipulated. This is the default and only mode in Java. But Ruby also has immutable strings called Symbols. Symbols are defined with colon (:) character followed by its value. Here is an example of a symbol:

okButtonLabel = :ok

By default, any Java string passed to Ruby code is transformed by JRuby into a mutable string. But you can create a symbol in Java and use it. Then JRuby will not convert the value to a mutable string, but to a symbol.

Creating a Ruby symbol in Java

Ruby runtime = container.getProvider().getRuntime();
RubySymbol rs = RubySymbol.newSymbol(rubyRuntime, blockName);

Welcome to the polyglot world where you will use more than one language to solve one problem. Each language has some advantages which you can combine all of them to create an application easier and faster. And thanks to the JVM objects are not tightened to a language, you can write an object in Groovy which is sent through Java and finally be executed by Ruby. In fact, that’s precisely what happens when you run Asciidoctor using the Asciidoctor Gradle plugin! As you may see JVM has delivered Schengen treaty to objects. Any object can be passed through different languages without any problem; your Ruby code can have a life outside the JVM too, and even run in pure JavaScript using Opal. It truly is ‘write once, run everywhere!’

For further reading about the challenges of getting Ruby to run on the JVM and be faster than any other Ruby, check out this slide deck by the JRuby lead, Charles Nutter:

Thanks for reading, feel free to leave me comments below or reach out on Twitter @alexsotob.



  • Oliver White

    Thanks for a great article Alex, this has tons of cool stuff for devs in there…

  • Phil Pirozhkov

    Immutable java strings are like freezed ruby strings, while ruby symbols are more like java enums.

    In benchmark you mention it’s more like GIL and running ruby servers on a single core played negative role, it’s not the upside of AOT or JIT.

  • Roberto Cortez

    Welcome to the crew Alex, great to have you here!

    I have to say that I never tried Ruby before, but after reading your post I will try :P

  • Disclaimer: I like Ruby, but…
    If you compare Ruby lang and Groovy lang you would found many similar features, even with different implementation. And to be pragmatic I’m suggesting to use Groovy in Java-based project and avoid mixing JRuby (and Jython) with Java.

    So, I would say Ruby (especially JRuby) is cool outside Java project(s). But, polyglot JVM programming might play a bad game with long-running projects, IMHO