Monday, January 14, 2008

Runnable Java Procs in JRuby

One of the cool features of the JRuby Swing GUI builder library, Profligacy (by the ever awesome Zed Shaw of Mongrel fame) is the Proc#to_runnable method that converts procs into a java.lang.Runnable interface that can be passed into any Java method that accepts an instance of Runnable, such as java.lang.Thread.new(). Profligacy's implementation looks something like this:

class RunnableProc
include java.lang.Runnable
def initialize &block
@block = block
end
def run
@block.call
end
end
class Proc
def to_runnable
RunnableProc.new &self
end
end


I prefer doing this instead:

class Proc
include java.lang.Runnable
alias_method :run, :call
end
p=Proc.new do
puts 'running'
end


The only disadvantage to that is that you can't use the familiar proc { ... } and lambda {...}, but I like having a simple 4-liner. And the Runnable interface is really useful in JRuby for working around protected Java methods when creating JRuby subclasses: I can mock up and compile a simple Java subclass that accepts a Runnable, then instantiate it in JRuby with a Proc. For example, the java.util.TimerTask class has a protected constructor, so you can't instantiate it in JRuby, even as a subclass, because a subclass is really a subclass of JavaProxy with an instance variable of the Java class. So:


//RubyTimerTask.java
public class RubyTimerTask extends java.util.TimerTask
{
public Runnable task;

public RubyTimerTask(Runnable r){
this.task = r;
}
public void run(){
this.task.run();
}
}

#timer_test.rb
include_class 'RubyTimerTask'
p = Proc.new { puts 'running' }
rtt = RubyTimerTask.new p
t=java.util.Timer.new
t.schedule rtt, 2000 #run in 2 seconds
t.cancel #join the Timer's thread

0 Comments:

Post a Comment

<< Home