The Pleasures of JRuby

On March 19, 2013 I gave a presentation at the Ruby User Group in Phoenix, AZ. I went on much longer than I really should have. The response to the talk was good, there were a lot good questions, and I showed a good number of examples. I think, though, that I may have gone over the code examples way too quickly.

There was one thing in particular that I find quite useful, and while I mentioned it (and had Vim up on the screen for about 30 seconds showing the code) I want to discus it more here. It’s a very powerful feature of JRuby, which is the main language I use for my Leap coding.

JRuby is an implementation in Java of the Ruby programming language. There are two notable virtues to this. One, it tends to be faster (modulo program start-up times that including the initialization of a JVM) than the standard C-based implementation of Ruby. Two, being written in Java you can load Java libraries and use them as if (more or less) they were Ruby libraries.

This is how I am able to use the Leap Motion Java jars in my code. It’s also how I use the Processing libraries for my UI.

That’s quite good.

But there’s yet another slick feature. In Ruby it is possible to re-open a class and add or change behavior. You can do this both for you own classes as well as the classes built-in to Ruby (or, for that matter, anyone else’s code you are using in your own program).

For example, Ruby provides an Array class. Arrays come with assorted built-in methods. Sometimes, though, you want for something that isn’t already provided.

Suppose you often are dealing with nested arrays, and want to get some kind of aggregate information, such as the total number of elements in all the arrays. There’s no built-in method that does exactly that, but here’s one way you could do it:



  def total_elements nested_ary
    nested_ary.inject(0) { | sum, ary|
      sum += ary.size
    }
  end

  a1 = %w{ a b c d}
  a2 = %w{ u v w x y }
  nested =  [a1, a2]

  total = total_elements nested 

  p total


Now whenever you need to get the total number of items in a nested array you can call that method.

Good idea?

One question is, should you even bother writing such a method? Well, if your program is doing this exactly once, or maybe twice, perhaps not. The implementation code is pretty short. You won’t go to code hell if you duplicated that code a bit.

On the other hand, compactness and avoidance of duplicate code are not the only reason to write methods. Often your code is easier to follow when you use well-named methods that express intent. Code is can also become readable when you are less distracted by the details of intermediate calculations. In other words, in a method that has an incidental use for the number of items in a nested array the code for actually calculating that total can be a distraction. Finally, you’ll may have noticed that this implementation assumes a single-level nesting. If for some reason yu find yourself dealing with nested nested arrays it’s easier to change the one method than to find and update every instance of the summation code.

I bring all this up because I’m going to take this a step further and much of the same reasoning applies. My goal here is not to convince you that this is or is not a good or right way to do things, but to show you something that you may (or may not) find useful for your own code. I happen to like it because I find it makes it easier for me to reason about my own code in certain circumstance.

Ruby allows you to re-open existing classes. This means you can mess with them! Don’t like how String#reverse behaves? Change it to return a string with letters in a random order! You can do it!

Actually, you probably don’t want to do that. However, there can be times when your use of an existing class would be improved my the addition of some behavior. For example, the Leap Motion API allows you to get a list of Hand objects from a Frame instance. From each Hand instance you can get a count of fingers. Suppose you want to know the total number of fingers in the current frame, regardless of what hand owns them? It’s easy to do:



  def total_fingers frame
    sum = 0
    return sum if frame.hands.size == 0

    frame.hands.each do |h|
      sum += h.fingers.size
    end
    sum
  end


Then, in onFrame, you could do this



  if 0 == total_fingers frame
    # No fingers anywhere!
  else
   # Do something with those fingers ..
  end


The thing is, I find that this would look nicer this way



  if 0 == frame.total_fingers
    # No fingers anywhere!
  else
   # Do something with those fingers ..
  end


Or suppose you want to get an array of all the fingers in the frame, regardless of what hand. It might be nice to be able to do this:



  if frame.all_fingers.empty?
    # No fingers anywhere!
  else
   # Do something with those fingers ..
  end


This is quite doable, even though the Hand and Frame classes written in Java and part of the SDK.

Mucking about in Java classes

To use LeapJava.jar in JRuby you basically just require that jar, and then make the package available by defining a module:


  require 'LeapJava.jar'

  import java.io.IOException
  import java.lang.Math

  module LeapMotion
    include_package 'com.leapmotion.leap'
  end

  include LeapMotion

  module Neurogami
    module Leap

      class Controller < LeapMotion::Controller
    
      end

    # more stuff ...
    end
  end

You can then create Leap class instances like this:


  include Neurogami::Leap

  @controller = Controller.new @some_listener_instance


However, if you want to dig into the classes directly you can do this: Java::ComLeapmotionLeap::Frame.

This allows us to mess around:



  class Java::ComLeapmotionLeap::Frame

    def all_fingers
      fingers = []
      return fingers if hands.empty?

      hands.each do |h|
        if h.fingers
          fingers.concat h.fingers
        end
      end

      fingers 
    end

  end


Now every instance of Frame will have the all_fingers method.

You can also change the built-in methods.

JRuby does a really good job of “Ruby-fying” Java classes; for example, if you are using a Java class with a method setFoo you can, in JRuby, invoke it as foo=.

However, I was finding that the ArrayList of hands and fingers was not responding to all of the Ruby Array methods I expected, so I decided to muck with the code:



  module Neurogami
    module Leap
      
      class Java::ComLeapmotionLeap::Frame
        alias_method :leap_hands,    :hands
        alias_method :leap_gestures, :gestures

        def hands
          leap_hands.to_a
        end

        def gestures
          leap_gestures.to_a
        end

      end

    end
  end

The downside to this is that every time you grab the list hands or gestures the code is recreating an array, so there’s some additional code overhead, but in actual practice I’ve not had any issues with this.

comments powered by Disqus