Archive

Posts Tagged ‘JRuby’

JRuby using ScriptEngine, invoking methods, passing args

March 4, 2010 Leave a comment

Doing the same job with JRuby was, if anything, even easier than getting Jython up and running. Download jar, classpath it, run up a couple of units to test POC and then a quick and dirty Hello World:

   ScriptEngine engine = new ScriptEngineManager().getEngineByName("jruby");
    String f = "puts 'JRuby says hello world' " ;
        try {
            engine.eval(f);
        } catch (ScriptException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

No indentation issues to concern myself with, and because JRuby in most cases is agnostic about double or single quotes for String representations, no escaping either. Now I want to play with some of my mixins and classes to see what happens. First up in my list of concerns is that most of my Ruby classes were written back in the day when mastodons walked the earth, when the command line interface was at the cutting edge of GUI design, and gems were rare and precious commodities. By a flickering candle’s light I crafted a cunning set of .rb modules to give me access to a number of utilities, one of which was a toolset for doing some basic math stuff which ruby lacked at the time. Now it’s probably all plug and play and not only will it do the math for you, it’ll probably make you tea and hand around the biscuits whilst doing so. Let’s consider the following power method which I’ve isolated from its friends and loved ones and put into solitary in a new file called testpow.rb.

# raise a number to power
def power( a, pow )
ctr = 1
b = a
  while ctr < pow
    b = a * b
    ctr += 1
  end
return b
end

We have two issues to deal with here. We need to call the method and also pass arguments to the method via the ScriptEngine. The way this is done is with the Invocable interface (the relevant JavaDoc is here).

Now all we need to do to make use of this method is something not a million light years removed from this:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("jruby");
String pathToRubyScripts = "X:/anon/productionScripts/"; // obviously make this appropriate to your .rb file locations
    FileReader fr = null;
    Invocable inv = null;
        try {
            fr = new FileReader(pathToRubyScripts + "testpow.rb");
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
              engine.eval(fr);
               inv = (Invocable) engine;
            try {
                long lg = (Long) inv.invokeFunction("power", 10,3); //invoke(String,Object args)
                System.out.println("Answer: " + lg);
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ScriptException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

Quietly I’m impressed with just how easy it is to implement scripting in Java.

Advertisements
Categories: Java Tags: , , ,

Embedding Jython script in Java with ScriptEngine…

March 3, 2010 1 comment

In an idle hour I did some more playing about with the Java ScriptEngine (see the earlier post on !Reinventing the Wheel) and decided to see just how easy it was to introduce another ScriptEngine into the mix. It was a toss-up between JRuby and Jython, but in the balance I went with Jython because it has certain benefits to work I frequently get engaged in relating to middleware, although I am altogether less familiar and comfortable with Jython/Python than JRuby/Ruby.

It was spectacularly easy, in fact depressingly so, not a technical challenge in sight. Download and classpath jar. Register Jython with ScriptEngine, run up a JUnit to test it’s available etc recycling the stringEval method outlined in the earlier post to test POC.

OK next up we want Java to be able to execute a Jython script proper. Here’s a simple Jython script to get the current directory (scarfed & modified from WebsphereTools):

import sys
import java.io as jio
currentdir = javaio.File (".")
print "Current directory : " + currentdir.getCanonicalPath()

Worked first time in standalone mode from Jython itself.

Next up is to see whether we can make it execute this script when embedded as a String in Java. Again depressingly easy.

static final private ScriptEngineManager sm = new ScriptEngineManager();
static final private ScriptEngine sEngine = sm.getEngineByName("jython");
static final String lsep = System.getProperty("line.separator");

public static void main(String[] args)
{
String a = "import sys" + lsep;
        a += "import java.io as javaio" + lsep;
        a+= "currentdir = javaio.File (\".\")" + lsep;
        a+= "print \"Current directory : \" + currentdir.getCanonicalPath()" + lsep;
       Object anon = runScript(a, "jython");
}

 public static Object runScript(String script, String engine) {
        Object res = "";
        if (engine.equals("jython")) {
            try {
                res = sEngine.eval(script);
            } catch (ScriptException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
return res;
}

Since I’m using NetBeans (can I say how much I love NetBeans again?) the answer this will print for me is:

Current directory : C:\Users\XXX\Documents\NetBeansProjects\TestEngineFactory (where XXX = my user base dir, names changed to protect the innocent for all the fairly obvious reasons).

The only real gotchas when doing something like this are to remember to ensure quotes are escaped correctly, that lines have a line separator and that you don’t trim or otherwise format incoming Jython script Strings when reading existing Jython scripts since Jython (being a Python superset) has those dull indentation rules etc.

Think I’ll stop blogging now and see how easy it is to do the same job with JRuby to access my arsenal of Ruby classes and mixins. I’ll let you know how I got on with an update later in the week.