I want to play with jruby, and I rewrite a numberguess example application from Echo2 framework into Ruby using JRuby. Let’s see… First we need to rewrite a NumberGuessServlet to load a NumberGuessApp ruby class instead of java class.
public class NumberGuessServlet extends WebContainerServlet {
Ruby runtime = Ruby.getDefaultInstance();
public NumberGuessServlet() {
super();
StringBuffer script = new StringBuffer();
URL url = NumberGuessServlet.class.getResource("NumberGuessApp.rb");
URI uri;
try {
uri = new URI(url.getFile());
File file = new File(uri.getPath());
BufferedReader fin = new BufferedReader(new FileReader(file));
String line = null;
while ((line = fin.readLine()) != null) {
script.append(line+"\n");
}
fin.close();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
try {
runtime.evalScript(script.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @see nextapp.echo2.webcontainer.WebContainerServlet#newApplicationInstance()
*/
public ApplicationInstance newApplicationInstance() {
Object numberGuessApp = runtime.evalScript("NumberGuessApp.new");
numberGuessApp = org.jruby.javasupport.JavaEmbedUtils.rubyToJava(runtime,
(org.jruby.runtime.builtin.IRubyObject) numberGuessApp, ApplicationInstance.class);
return (ApplicationInstance) numberGuessApp;
}
}
Now we have to write a ruby class.
Create a NumberGuessApp.rb
and include a Java magic
include Java
This make all Java stuff available in ruby. Next we need to include Echo2 stuff.
module Echo2
include_class 'nextapp.echo2.app.ApplicationInstance'
include_class 'nextapp.echo2.app.Button'
include_class 'nextapp.echo2.app.Color'
include_class 'nextapp.echo2.app.ContentPane'
include_class 'nextapp.echo2.app.Extent'
include_class 'nextapp.echo2.app.Insets'
include_class 'nextapp.echo2.app.Label'
include_class 'nextapp.echo2.app.ResourceImageReference'
include_class 'nextapp.echo2.app.Column'
include_class 'nextapp.echo2.app.TextField'
include_class 'nextapp.echo2.app.Window'
include_class 'nextapp.echo2.app.event.ActionEvent'
include_class 'nextapp.echo2.app.event.ActionListener'
include_class 'nextapp.echo2.app.layout.ColumnLayoutData'
end
This makes all Echo2 lib namespaced. Don’t forget to prefix Echo2 classes with Echo2::. Next big thing is casts. We can’t make a cast in ruby. But we can make something like this. We need a NumberGuessApp instance, lets make a simple method that return it:
class NumberGuessApp < Echo2::ApplicationInstance
def self.instance
@@instance
end
def init
@@instance = self
end
end
now instead of this:
((NumberGuessApp) ApplicationInstance.getActive())
we can write:
NumberGuessApp.instance
getActive() method probably do something more, but this is enough for this app. Nice feature of JRuby is that we can change all method and variables names to fit ruby style, don’t need to use any setters and getters. For example you can write:
@window.title = "Echo2 Guess-A-Number"
layout_column.cell_spacing = Echo2::Extent.new(10)
submit_button.add_action_listener(self)
But there is one problem. All methods that overrides included interfaces need to have a java names:
def actionPerformed(event)
end
Take a look at CongratulationsPane. Constructor have an argument, but it’s don’t want to work with jruby. We have to delete it. There will be no information about number of tries on congratulation screen. Sorry :) All variables are initialized in constructor (initialize method). For example:
def initialize
#
# Randomly generated number between 1 and 100 inclusive.
#
@random_number = rand 100
end
Static variables like colors should looks like this:
@guess_entry_field.foreground = Echo2::Color::WHITE
All source files are here. If you want to run it download all required jar files and copy it to lib.
Echo2 files are from echo2 package. Start ant. Copy a war file into your application server and launch it.