• RedBridge is an implementation of JSR223 on top of JRuby Embed API


    RedBridge: Wiki: Home — Project Kenai

    RedBridge Wiki

    This project is merging into JRuby Embed. Please see JRuby Embed Wiki.

    RedBridge is an implementation of JSR223 Scripting for the Java Platform on top of JRuby Embed API. Inheriting the features of JRuby Embed API, RedBridge enables to share various types of variables and constants between Java and Ruby. In addition, users can choose a Ruby runtime and other resources' instance type from threadsafe, singlethread, and singleton.

    Download

    RedBridge version is 0.0.1.1 is available to download at:

    http://kenai.com/projects/redbridge/downloads

    RedBridge needs patched JRuby and JRuby Embed API, both of which are at http://kenai.com/projects/jruby-embed/downloads.

    Configurations

    You can configure RedBridge(JRuby engine) using System properties. Currently, class paths, a context instance model, and local variables' behavior can be configured.

    Class Path

    Propety Name: org.jruby.embed.class.path (or java.class.path)

    Either org.jruby.embed.class.path or java.class.path property names is used to configure class path to load jar archive and/or ruby scripts. RedBridge sees org.jruby.embed.class.path first. When no path is tied to the name, org.jruby.embed.class.path, RedBridge sees java.class.path next. The format of the paths is the same of Java's class path syntax, so :(colon) separated path string on Unix and OS X or ;(semi-colon) separated one on Windows Be sure to set classpaths before you instantiate (JRuby)ScriptEngineManager.

    Example:

    1.String classPath = "/Users/yoko/Tools/jruby-1.3.1/lib/ruby/1.8";
    2.System.setProperty("org.jruby.embed.class.path", classPath);
    3.ScriptEngineManager manager = new ScriptEngineManager();
    4.// for OS X users
    5.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    6.ScriptEngine engine = manager.getEngineByName("jruby");

    Context Instance Model

    Property Name: org.jruby.embed.localcontext.scope
    Value: theadsafe (default), singlethread, or singleton

    A context of RedBridge holds context specific values such as name-value pairs for sharing variables between Java and Ruby, Ruby runtime, defautl I/O streams, and a few more. These context specific values are saved in one of three types, threadsafe, singlethread, and singleton. Like class path setting, be sure to set the model before you instantiate (JRuby)ScriptEngineManager.

    • ThreadSafe

    Default. Script's parsings and evaluations should be safely performed on a multi-threaded environment such as servlet container. A supposed usage is that ScriptEngine is instantiateted in servlet's init() method and evaluates scripts in servlet's service() method.
    Example:

    1.System.setProperty("org.jruby.embed.localcontext.scope", "threadsafe");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");
    • SingleThread

    This model pretends as if there is only one thread in the world, and does not mind race condition at all. Users are resposnsible to thread safety. If you want to instantiate ScriptEngine in servlet's service() method, this model would be the best suited one.
    Example:

    1.System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");
    • Singleton

    This model uses a well known Singleton pattern, and the only one instance of a local context will exist on JVM.
    Example:

    1.System.setProperty("org.jruby.embed.localcontext.scope", "singleton");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");

    Local Variable Behavior

    Property Name: org.jruby.embed.localvariable.behavior
    Value: transient (default), persistent, or global

    RedBrdige enables to share Ruby's local, instance, global variables, and constants. To share these variables between Ruby and Java, RedBridge offers three types of local variable behaviors, transient, persistent, and global.

    • Transient Local Variable Behavior

    Default. Variables' scope is faithful to Ruby semantics, so local variable does not survive over the multiple evaluations. After the each evaluation, local variable will vanish. However, instance and global variables, and constants survive unless those are removed explicitly. If you use global variables, the variables can be referred literally globally in Ruby runtime and exist as long as the runtime is alive.
    Example:

    1.System.setProperty("org.jruby.embed.localvariable.behavior", "transient");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");
    • Persistent Local Variable Behavior

    When this type is chosen, RedBridge keeps sharing all local variables' over multiple evaluations. This might not be a semantically correct usage, but is useful in some cases especially for users who have BSF background.
    Example:

    1.System.setProperty("org.jruby.embed.localvariable.behavior", "persistent");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");
    • Global Local Variable Behavior

    This behavior might be convenient to users who have used JSR 223 reference implementation released at scripging.dev.java.net and don't want change any code. With names like Ruby's local variable name, variables are mapped to Ruby's global variables.Only global variables can be shared between Ruby and Java, when this behavior is chosen.
    Example:

    1.System.setProperty("org.jruby.embed.localvariable.behavior", "global");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");

    CompileMode

    Property Name: org.jruby.embed.compilemode
    Value: off (default), jit, or force

    Experimental feature. JRuby has two options to compile Ruby scripts. This configuration provides users a way fo setting a compile mode. When jit or force is specified, only a global variable can be shared between Ruby and Java.

    Example:

    1.System.setProperty("org.jruby.embed.compilemode", "jit");
    2.ScriptEngineManager manager = new ScriptEngineManager();
    3.// for OS X users
    4.//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    5.ScriptEngine engine = manager.getEngineByName("jruby");

    Line Number

    Attribute Name: org.jruby.embed.linenumber
    Value: 1, 2, 3,,,, (integer)

    When you want to specify a line number to display for parse errors and backtraces, use this attribute.

    Example:

    01.import javax.script.ScriptContext;
    02.import javax.script.ScriptEngine;
    03.import javax.script.ScriptException;
    04.import org.jruby.embed.jsr223.JRubyScriptEngineManager;
    05. 
    06.public class LineNumberSample {
    07.    private final String script =
    08.            "puts \"Hello World.\"\n" +
    09.            "puts \"Error is here.";
    10. 
    11.    private LineNumberSample() throws ScriptException {
    12.        JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
    13.        ScriptEngine engine = manager.getEngineByName("jruby");
    14.        try {
    15.            engine.eval(script);    // Since no line number is given, 0 is applied to.
    16.        } catch (Exception e) {
    17.            ;
    18.        }
    19.        try {
    20.            engine.getContext().setAttribute("org.jruby.embed.linenumber", 1, ScriptContext.ENGINE_SCOPE);
    21.            engine.eval(script);
    22.        } catch (Exception e) {
    23.            ;
    24.        }
    25.        try {
    26.            engine.getContext().setAttribute("org.jruby.embed.linenumber", 2, ScriptContext.ENGINE_SCOPE);
    27.            engine.eval(script);
    28.        } catch (Exception e) {
    29.            ;
    30.        }
    31.    }
    32. 
    33.    public static void main(String[] args)
    34.            throws ScriptException {
    35.        new LineNumberSample();
    36.    }
    37.}

    Outpus:

    :1: <script>:2: unterminated string meets end of file (SyntaxError)
    :1: <script>:3: unterminated string meets end of file (SyntaxError)
    :1: <script>:4: unterminated string meets end of file (SyntaxError)
    

    ScriptEngineManager for JRuby

    RedBridge has a JRubyScriptEngineManager class defined, which is used as a substitue of javax.script.ScriptEngineManager. This class is mainly for OS X users. OS X users have had a problem when they use JRuby engine on JDK 1.5 and have JDK 1.6 in their System. After Java update 4 has been installed, JRuby engine can't be instantiated in a JSR 223 way even on JDK 1.6. This class fixes this kind of issue.

    If no classloader is set in the argument of JRubyScriptEngineManager constructor, JRubyScriptEngineManager uses system classloader to find jar archives of JSR 223 engines. You can set an appropriate classloader to the constructor. The example below uses Thread.currentThread().getContextClassLoader().

    Example:

    1.JRubyScriptEngineManager manager = new JRubyScriptEngineManager(Thread.currentThread().getContextClassLoader());
    2.ScriptEngine engine = manager.getEngineByName("jruby");

    Code Examples

    Simple Eval

    01.package redbridge;
    02. 
    03.import javax.script.ScriptEngine;
    04.import javax.script.ScriptEngineManager;
    05.import javax.script.ScriptException;
    06. 
    07.public class EvalStringSample {
    08. 
    09.    private EvalStringSample() throws ScriptException {
    10.        System.out.println("[" + getClass().getName() + "]");
    11.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    12.        System.setProperty("org.jruby.embed.localvariable.behavior", "persistent");
    13.        ScriptEngineManager manager = new ScriptEngineManager();
    14.        ScriptEngine engine = manager.getEngineByName("jruby");
    15.        engine.eval("p=9.0");
    16.        engine.eval("q = Math.sqrt p");
    17.        engine.eval("puts \"square root of #{p} is #{q}\"");
    18.        System.out.println("q = " + engine.get("q"));
    19.    }
    20. 
    21.    public static void main(String[] args) throws ScriptException {
    22.        new EvalStringSample();
    23.    }
    24.}

    Output

    [redbridge.EvalStringSample]
    square root of 9.0 is 3.0
    q = 3.0
    

    Local variables survive over multiple eval() invocations. Variables and constants defined only in Ruby scripts are available to use in Java after scripts are evaluated.

    Simple Eval 2

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.ScriptEngine;
    07.import javax.script.ScriptEngineManager;
    08.import javax.script.ScriptException;
    09. 
    10.public class EvalReaderSample {
    11.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    12. 
    13.    private EvalReaderSample() throws ScriptException, FileNotFoundException {
    14.        System.out.println("[" + getClass().getName() + "]");
    15.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    16.        ScriptEngineManager manager = new ScriptEngineManager();
    17.        ScriptEngine engine = manager.getEngineByName("jruby");
    18.        String filename = basedir + "/src/ruby/calendar.rb";
    19.        Reader reader = new FileReader(filename);
    20.        Object result = engine.eval(reader);
    21.        System.out.println("Next year is " + result + ".");
    22.    }
    23. 
    24.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    25.        new EvalReaderSample();
    26.    }
    27.}
    01.# calendar.rb [Birch]
    02. 
    03.require 'date'
    04. 
    05.class Calendar
    06.  def initialize
    07.    @today = DateTime.now
    08.  end
    09. 
    10.  def next_year
    11.    @today.year + 1
    12.  end
    13.end
    14.c = Calendar.new
    15.c.next_year
    Output
    [redbridge.EvalReaderSample]
    Next year is 2010.
    

    Eval with Bindings

    A constant, PI, is injected Ruby by Java.

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import javax.script.Bindings;
    05.import javax.script.ScriptContext;
    06.import javax.script.ScriptEngine;
    07.import javax.script.ScriptEngineManager;
    08.import javax.script.ScriptException;
    09.import javax.script.SimpleBindings;
    10. 
    11.public class EvalStringBindingsSample {
    12. 
    13.    private EvalStringBindingsSample() throws ScriptException, FileNotFoundException {
    14.        System.out.println("[" + getClass().getName() + "]");
    15.        ScriptEngineManager manager = new ScriptEngineManager();
    16.        ScriptEngine engine = manager.getEngineByName("jruby");
    17.        String script =
    18.            "def get_perimeter(x, y)\n" +
    19.              "x + 2.0 * y + PI / 2.0 * x\n" +
    20.            "end\n" +
    21.            "get_perimeter(1.5, 1.5)";
    22.        Bindings bindings = new SimpleBindings();
    23.        bindings.put("PI", 3.1415);
    24.        Double result = (Double) engine.eval(script, bindings);
    25.        System.out.println(result.toString());
    26.    }
    27. 
    28.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    29.        new EvalStringBindingsSample();
    30.    }
    31.}
    Output
    [redbridge.EvalStringBindingsSample]
    6.8561250000000005
    

    Eval with Bindings 2

    Tow instance variables, @month and @day, are injected Ruby by Java.

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.Bindings;
    07.import javax.script.ScriptContext;
    08.import javax.script.ScriptEngine;
    09.import javax.script.ScriptEngineManager;
    10.import javax.script.ScriptException;
    11.import javax.script.SimpleBindings;
    12. 
    13.public class EvalReaderBindingsSample {
    14.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    15. 
    16.    private EvalReaderBindingsSample() throws ScriptException, FileNotFoundException {
    17.        System.out.println("[" + getClass().getName() + "]");
    18.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    19.        ScriptEngineManager manager = new ScriptEngineManager();
    20.        ScriptEngine engine = manager.getEngineByName("jruby");
    21.        String filename = basedir + "/src/ruby/count_down.rb";
    22.        Reader reader = new FileReader(filename);
    23.        Bindings bindings = new SimpleBindings();
    24.        bindings.put("@month", 1);
    25.        bindings.put("@day", 1);
    26.        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
    27.        String result = (String) engine.eval(reader, bindings);
    28.        System.out.println(result.toString());
    29.    }
    30. 
    31.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    32.        new EvalReaderBindingsSample();
    33.    }
    34.}
    01.# count_down.rb [Birch]
    02. 
    03.require 'date'
    04. 
    05.def count_down_birthday
    06.  now = DateTime.now
    07.  year = now.year
    08.  days = DateTime.new(year, @month, @day).yday - now.yday
    09.  if days < 0
    10.    this_year = DateTime.new(year, 12, 31).yday - now.yday
    11.    next_year = DateTime.new(year + 1, @month, @day).yday
    12.    days = this_year + next_year
    13.  end
    14.  return "Happy Birthday!" if days == 0
    15.  return "You have #{days} day(s) to your next birthday!"
    16.end
    17.count_down_birthday
    Output
    [redbridge.EvalReaderBindingsSample]
    You have 210 day(s) to your next birthday!
    

    Eval with ScriptContext

    01.package redbridge;
    02. 
    03.import java.util.List;
    04.import javax.script.ScriptContext;
    05.import javax.script.ScriptEngine;
    06.import javax.script.ScriptEngineManager;
    07.import javax.script.ScriptException;
    08.import javax.script.SimpleScriptContext;
    09. 
    10.public class EvalStringScriptContextSample {
    11. 
    12.    private EvalStringScriptContextSample() throws ScriptException {
    13.        System.out.println("[" + getClass().getName() + "]");
    14.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    15.        ScriptEngineManager manager = new ScriptEngineManager();
    16.        ScriptEngine engine = manager.getEngineByName("jruby");
    17.        String script =
    18.            "def norman_window(x, y)\n" +
    19.               "return get_area(x, y), get_perimeter(x, y)\n" +
    20.            "end\n" +
    21.            "def get_area(x, y)\n" +
    22.              "x * y + Math::PI / 8.0 * x ** 2.0\n" +
    23.            "end\n" +
    24.            "def get_perimeter(x, y)\n" +
    25.              "x + 2.0 * y + Math::PI / 2.0 * x\n" +
    26.            "end\n" +
    27.            "norman_window width, height";
    28.        ScriptContext context = new SimpleScriptContext();
    29.        context.setAttribute("width", 1, ScriptContext.ENGINE_SCOPE);
    30.        context.setAttribute("height", 3, ScriptContext.ENGINE_SCOPE);
    31.        List<Double> result = (List<Double>) engine.eval(script, context);
    32.        for (int i=0; i<result.size(); i++) {
    33.            System.out.println(result.get(i));
    34.        }
    35.    }
    36. 
    37.    public static void main(String[] args) throws ScriptException {
    38.        new EvalStringScriptContextSample();
    39.    }
    40.}
    Output
    [redbridge.EvalStringScriptContextSample]
    :1 warning: already initialized constant STDOUT
    :1 warning: already initialized constant STDERR
    3.392699081698724
    8.570796326794897
    

    Eval with ScriptContext 2

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import java.util.List;
    07.import javax.script.ScriptContext;
    08.import javax.script.ScriptEngine;
    09.import javax.script.ScriptEngineManager;
    10.import javax.script.ScriptException;
    11.import javax.script.SimpleScriptContext;
    12. 
    13.public class EvalReaderScriptContextSample {
    14.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    15. 
    16.    private EvalReaderScriptContextSample() throws ScriptException, FileNotFoundException {
    17.        System.out.println("[" + getClass().getName() + "]");
    18.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    19.        ScriptEngineManager manager = new ScriptEngineManager();
    20.        ScriptEngine engine = manager.getEngineByName("jruby");
    21.        String filename = basedir + "/src/ruby/norman_window_dimensions2.rb";
    22.        Reader reader = new FileReader(filename);
    23.        ScriptContext context = new SimpleScriptContext();
    24.        context.setAttribute("@x", 4.0, ScriptContext.ENGINE_SCOPE);
    25.        context.setAttribute("@y", 1.0, ScriptContext.ENGINE_SCOPE);
    26.        List<Double> result = (List<Double>) engine.eval(reader, context);
    27.        for (int i=0; i<result.size(); i++) {
    28.            System.out.println(result.get(i));
    29.        }
    30.    }
    31. 
    32.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    33.        new EvalReaderScriptContextSample();
    34.    }
    35.}
    01.#norman_window_dimensions2.rb [Birch]
    02. 
    03.def norman_window
    04.  return get_area, get_perimeter
    05.end
    06. 
    07.def get_area
    08.  @x * @y + Math::PI / 8.0 * @x ** 2.0
    09.end
    10. 
    11.def get_perimeter
    12.  @x + 2.0 * @y + Math::PI / 2.0 * @x
    13.end
    14. 
    15.norman_window
    Output
    [redbridge.EvalReaderScriptContextSample]
    :1 warning: already initialized constant STDOUT
    :1 warning: already initialized constant STDERR
    10.283185307179586
    12.283185307179586
    

    Parse Once, Eval Many Times

    01.package redbridge;
    02. 
    03.import javax.script.Compilable;
    04.import javax.script.CompiledScript;
    05.import javax.script.ScriptEngine;
    06.import javax.script.ScriptEngineManager;
    07.import javax.script.ScriptException;
    08. 
    09.public class CompileStringSample {
    10. 
    11.    private CompileStringSample() throws ScriptException {
    12.        System.out.println("[" + getClass().getName() + "]");
    13.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    14.        ScriptEngineManager manager = new ScriptEngineManager();
    15.        ScriptEngine engine = manager.getEngineByName("jruby");
    16.        String script =
    17.            "def norman_window(x, y)\n" +
    18.               "puts \"Dimensions of a #{x} x #{y} Norman window are\"\n" +
    19.               "puts \"area: #{get_area(x, y)}\"\n" +
    20.               "puts \"perimeter: #{get_perimeter(x, y)}\"\n" +
    21.            "end\n" +
    22.            "def get_area(x, y)\n" +
    23.              "x * y + Math::PI / 8.0 * x ** 2.0\n" +
    24.            "end\n" +
    25.            "def get_perimeter(x, y)\n" +
    26.              "x + 2.0 * y + Math::PI / 2.0 * x\n" +
    27.            "end\n" +
    28.            "norman_window width, height";
    29.        engine.put("width", 2);
    30.        engine.put("height", 1);
    31.        CompiledScript cs = ((Compilable)engine).compile(script);
    32.        cs.eval();
    33.        engine.put("width", 1);
    34.        engine.put("height", 2);
    35.        cs.eval();
    36.        engine.put("width", 2);
    37.        engine.put("height", 2);
    38.        cs.eval();
    39.    }
    40. 
    41.    public static void main(String[] args) throws ScriptException {
    42.        new CompileStringSample();
    43.    }
    44.}

    Output

    [redbridge.CompileStringSample]
    Dimensions of a 2 x 1 Norman window are
    area: 3.5707963267949
    perimeter: 7.14159265358979
    Dimensions of a 1 x 2 Norman window are
    area: 2.39269908169872
    perimeter: 6.5707963267949
    Dimensions of a 2 x 2 Norman window are
    area: 5.5707963267949
    perimeter: 9.14159265358979
    

    After the parsing, setting different values to the "width" and "height" local variables, this program repeats eval three times in total. This feature would work well with Java Servlet. What if a Servlet parses Ruby scripts once in its init() method and just execute them in every HTTP request? Probably, we can expect performance improvement.

    In future release, I want to add a compile-once-execute-many-times feature.

    Java Interface Implementation

    Java Interface

    1.package redbridge;
    2. 
    3.public interface Sphere {
    4.    double volume(double radius);
    5.    double surface_area(double radius);
    6.}

    Ruby Implementation

    1.# sphere.rb [Birch]
    2.def volume(r)
    3.  4.0 / 3.0 * Math::PI * r ** 3.0
    4.end
    5. 
    6.def surface_area(r)
    7.  4.0 * Math::PI * r ** 2.0
    8.end

    Usage

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.Invocable;
    07.import javax.script.ScriptEngine;
    08.import javax.script.ScriptEngineManager;
    09.import javax.script.ScriptException;
    10. 
    11.public class GetInterfaceSample {
    12.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    13. 
    14.    private GetInterfaceSample() throws ScriptException, FileNotFoundException {
    15.        System.out.println("[" + getClass().getName() + "]");
    16.        ScriptEngineManager manager = new ScriptEngineManager();
    17.        ScriptEngine engine = manager.getEngineByName("jruby");
    18.        String filename = basedir + "/src/ruby/sphere.rb";
    19.        Reader reader = new FileReader(filename);
    20.        engine.eval(reader);
    21.        Sphere sphere = ((Invocable)engine).getInterface(Sphere.class);
    22.        double radius = 3.0;
    23.        System.out.println("Volume of a " + radius + " radius sphere is " + sphere.volume(radius));
    24.        System.out.println("Surface area of a " + radius + " radius sphere is " + sphere.surface_area(radius));
    25.        radius = 4;
    26.        System.out.println("Volume of a " + radius + " radius sphere is " + sphere.volume(radius));
    27.        System.out.println("Surface area of a " + radius + " radius sphere is " + sphere.surface_area(radius));
    28.    }
    29. 
    30.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    31.        new GetInterfaceSample();
    32.    }
    33.}

    Output

    [redbridge.GetInterfaceSample]
    Volume of a 3.0 radius sphere is 113.09733552923254
    Surface area of a 3.0 radius sphere is 113.09733552923255
    Volume of a 4.0 radius sphere is 268.082573106329
    Surface area of a 4.0 radius sphere is 201.06192982974676
    

    Java Interface Implementation 2

    Java Interface

    1.package redbridge;
    2. 
    3.public interface PositionFunction {
    4.    String velocity(double t);
    5.    String position(double t);
    6.}

    Ruby Implementation

    01.# position_function.rb [Birch]
    02. 
    03.class PositionFunction
    04.  include Java::redbridge.PositionFunction
    05.  attr :v0, :s0
    06.  def initialize(v0, s0, system)
    07.    @v0 = v0
    08.    @s0 = s0
    09.    if "english" == system.downcase
    10.      @g = -32.0
    11.      @unit_v = "ft./sec"
    12.      @unit_s = "ft."
    13.    end
    14.    if "metric" == system.downcase
    15.      @g = -9.8
    16.      @unit_v = "m/sec"
    17.      @unit_s = "m"
    18.    end
    19.  end
    20. 
    21.  def position(t)
    22.    "#{1.0 / 2.0 * @g * t ** 2.0 + @v0 * t + @s0} #{@unit_s}"
    23.  end
    24.   
    25.  def velocity(t)
    26.    "#{@g * t + @v0} #{@unit_v}"
    27.  end
    28.end
    29.PositionFunction.new(initial_velocity, initial_height, system)

    Usage

    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.Bindings;
    07.import javax.script.Invocable;
    08.import javax.script.ScriptEngine;
    09.import javax.script.ScriptEngineManager;
    10.import javax.script.ScriptException;
    11. 
    12.public class GetInterfaceWithReceiverSample {
    13.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    14. 
    15.    private GetInterfaceWithReceiverSample() throws ScriptException, FileNotFoundException {
    16.        System.out.println("[" + getClass().getName() + "]");
    17.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    18.        ScriptEngineManager manager = new ScriptEngineManager();
    19.        ScriptEngine engine = manager.getEngineByName("jruby");
    20.        String filename = basedir + "/src/ruby/position_function.rb";
    21.        Reader reader = new FileReader(filename);
    22.        Bindings bindings = engine.createBindings();
    23.        bindings.put("initial_velocity", 30.0);
    24.        bindings.put("initial_height", 30.0);
    25.        bindings.put("system", "metric");
    26.        Object receiver = engine.eval(reader, bindings);
    27.        PositionFunction pf = ((Invocable)engine).getInterface(receiver, PositionFunction.class);
    28.        double t = 3.0;
    29.        System.out.println("Height after " + t + " sec is " + pf.position(t));
    30.        t = 1.0;
    31.        System.out.println("Velocity after " + t + " sec is " + pf.velocity(t));
    32. 
    33.        reader = new FileReader(filename);
    34.        bindings = engine.createBindings();
    35.        bindings.put("initial_velocity", 30.0);
    36.        bindings.put("initial_height", 30.0);
    37.        bindings.put("system", "english");
    38.        receiver = engine.eval(reader, bindings);
    39.        pf = ((Invocable)engine).getInterface(receiver, PositionFunction.class);
    40.        t = 2.0;
    41.        System.out.println("Height after " + t + " sec is " + pf.position(t));
    42.        System.out.println("Velocity after " + t + " sec is " + pf.velocity(t));
    43.    }
    44. 
    45.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    46.        new GetInterfaceWithReceiverSample();
    47.    }
    48.}

    Output

    [redbridge.GetInterfaceWithReceiverSample]
    Height after 3.0 sec is 75.9 m
    Velocity after 1.0 sec is 20.2 m/sec
    Height after 2.0 sec is 26.0 ft.
    Velocity after 2.0 sec is -34.0 ft./sec
    

    Method Invocation: invokeFunction

    Ruby

    01.# count_down.rb [Birch]
    02. 
    03.require 'date'
    04. 
    05.def count_down_birthday
    06.  now = DateTime.now
    07.  year = now.year
    08.  days = DateTime.new(year, @month, @day).yday - now.yday
    09.  if days < 0
    10.    this_year = DateTime.new(year, 12, 31).yday - now.yday
    11.    next_year = DateTime.new(year + 1, @month, @day).yday
    12.    days = this_year + next_year
    13.  end
    14.  return "Happy Birthday!" if days == 0
    15.  return "You have #{days} day(s) to your next birthday!"
    16.end
    17.count_down_birthday
    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.Bindings;
    07.import javax.script.Invocable;
    08.import javax.script.ScriptContext;
    09.import javax.script.ScriptEngine;
    10.import javax.script.ScriptEngineManager;
    11.import javax.script.ScriptException;
    12.import javax.script.SimpleBindings;
    13. 
    14.public class InvokeFunctionSample {
    15.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    16. 
    17.    private InvokeFunctionSample() throws ScriptException, FileNotFoundException, NoSuchMethodException {
    18.        System.out.println("[" + getClass().getName() + "]");
    19.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    20.        ScriptEngineManager manager = new ScriptEngineManager();
    21.        ScriptEngine engine = manager.getEngineByName("jruby");
    22.        String filename = basedir + "/src/ruby/count_down.rb";
    23.        Reader reader = new FileReader(filename);
    24.        Bindings bindings = new SimpleBindings();
    25.        bindings.put("@month", 6);
    26.        bindings.put("@day", 6);
    27.        Object result = engine.eval(reader, bindings);
    28.        System.out.println(result.toString());
    29. 
    30.        String method = "count_down_birthday";
    31.        bindings.put("@month", 12);
    32.        bindings.put("@day", 31);
    33.        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
    34.        Object[] args = null;
    35.        result = ((Invocable)engine).invokeFunction(method, args);
    36.        System.out.println(result.toString());
    37.        bindings.put("@month", 6);
    38.        bindings.put("@day", 3);
    39.        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
    40.        result = ((Invocable)engine).invokeFunction(method, args);
    41.        System.out.println(result.toString());
    42.    }
    43. 
    44.    public static void main(String[] args) throws ScriptException, FileNotFoundException, NoSuchMethodException {
    45.        new InvokeFunctionSample();
    46.    }
    47.}
    Output
    [redbridge.InvokeFunctionSample]
    Happy Birthday!
    You have 208 day(s) to your next birthday!
    You have 362 day(s) to your next birthday!
    

    Method Invocation2: invokeMethod

    Ruby

    01.# tree_with_localvars.rb [Birch]
    02. 
    03.class Tree
    04.  attr_reader :name, :shape, :foliage, :flower
    05.  def initialize(name, shape, foliage, flower)
    06.    @name = name
    07.    @shape = shape
    08.    @foliage = foliage
    09.    @flower = flower
    10.  end
    11.  def to_s
    12.    "#{name.capitalize} is a #{shape} shaped, #{foliage} tree, and blooms #{flower.color} flowers in #{flower.bloomtime}."
    13.  end
    14.  def update(color, bloomtime)
    15.    @flower.color = color
    16.    @flower.bloomtime = bloomtime
    17.  end
    18.end
    19. 
    20.class Flower
    21.  attr_accessor :color, :bloomtime
    22.  def initialize(color, bloomtime)
    23.    @color = color
    24.    @bloomtime = bloomtime
    25.  end
    26.end
    27. 
    28.Tree.new(name, shape, foliage, Flower.new(color, bloomtime))
    01.package redbridge;
    02. 
    03.import java.io.FileNotFoundException;
    04.import java.io.FileReader;
    05.import java.io.Reader;
    06.import javax.script.Bindings;
    07.import javax.script.Invocable;
    08.import javax.script.ScriptContext;
    09.import javax.script.ScriptEngine;
    10.import javax.script.ScriptEngineManager;
    11.import javax.script.ScriptException;
    12.import javax.script.SimpleBindings;
    13. 
    14.public class InvokeMethodSample {
    15.    private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
    16. 
    17.    private InvokeMethodSample() throws ScriptException, FileNotFoundException, NoSuchMethodException {
    18.        System.out.println("[" + getClass().getName() + "]");
    19.        System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
    20.        ScriptEngineManager manager = new ScriptEngineManager();
    21.        ScriptEngine engine = manager.getEngineByName("jruby");
    22.        String filename = basedir + "/src/ruby/tree_with_localvars.rb";
    23.        Reader reader = new FileReader(filename);
    24.        Bindings bindings = new SimpleBindings();
    25.        bindings.put("name", "cedar");
    26.        bindings.put("shape", "pyramidal");
    27.        bindings.put("foliage", "evergreen");
    28.        bindings.put("color", "nondescript");
    29.        bindings.put("bloomtime", "April - May");
    30.        Object receiver = engine.eval(reader, bindings);
    31.        Object[] args = null;
    32.        String result = (String) ((Invocable)engine).invokeMethod(receiver, "to_s", args);
    33.        System.out.println(result);
    34. 
    35.        args = new Object[]{"pink", "March - April"};
    36.        ((Invocable)engine).invokeMethod(receiver, "update", args);
    37.        bindings.put("@name", "cherry blossom");
    38.        bindings.put("@shape", "round");
    39.        bindings.put("@foliage", "deciduous");
    40.        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
    41.        args = null;
    42.        result = (String) ((Invocable)engine).invokeMethod(receiver, "to_s", args);
    43.        System.out.println(result);
    44.    }
    45. 
    46.    public static void main(String[] args) throws ScriptException, FileNotFoundException, NoSuchMethodException {
    47.        new InvokeMethodSample();
    48.    }
    49.}
    Output
    [redbridge.InvokeMethodSample]
    Cedar is a pyramidal shaped, evergreen tree, and blooms nondescript flowers in April - May.
    Cherry blossom is a round shaped, deciduous tree, and blooms pink flowers in March - April.
    

    Compile(not just parsing, real compilation) Mode

    001.package redbridge;
    002. 
    003.import java.io.FileNotFoundException;
    004.import java.io.FileReader;
    005.import java.io.Reader;
    006.import java.util.Calendar;
    007.import javax.script.Compilable;
    008.import javax.script.CompiledScript;
    009.import javax.script.ScriptEngine;
    010.import javax.script.ScriptEngineManager;
    011.import javax.script.ScriptException;
    012. 
    013.public class CompiledModeSample {
    014.    private final static String jrubyhome = "/Users/yoko/Tools/jruby-1.3.0";
    015.    private int iteration = 50;
    016. 
    017.    private CompiledModeSample() throws ScriptException, FileNotFoundException {
    018.        System.out.println("[" + getClass().getName() + "]");
    019.        System.setProperty("org.jruby.embed.localcontext.scope", "singleton");
    020.        setLoadPaths();
    021.        String filename = jrubyhome + "/test/testEnumerator.rb";
    022.        Reader reader = new FileReader(filename);
    023.        runWithCompileModeOff(reader);
    024.        runWithCompileModeForce(reader);
    025.        runWithCompileModeJit(reader);
    026. 
    027.        runMultipleTimesWithModeOff(reader);
    028.        runMultipleTimesWithModeForce(reader);
    029.        runMultipleTimesWithModeJit(reader);
    030.    }
    031. 
    032.    private void setLoadPaths() {
    033.        String[] paths = {
    034.            jrubyhome + "/lib/ruby/1.8",
    035.            jrubyhome + "/lib/ruby/site_ruby/1.8",
    036.            jrubyhome
    037.        };
    038.        String separator = System.getProperty("path.separator");
    039.        String classPath = "";
    040.        for (int i=0; i < paths.length; i++) {
    041.            classPath = classPath + paths[i] + separator;
    042.        }
    043.        classPath = classPath.substring(0, classPath.length()-1);
    044.        System.setProperty("org.jruby.embed.class.path", classPath);
    045.    }
    046. 
    047.    private void runWithCompileModeOff(Reader reader) throws ScriptException {
    048.        ScriptEngineManager manager = new ScriptEngineManager();
    049.        ScriptEngine engine = manager.getEngineByName("jruby");
    050.        engine.eval(reader);
    051.        long start = Calendar.getInstance().getTimeInMillis();
    052.        engine.eval(reader);
    053.        long end = Calendar.getInstance().getTimeInMillis();
    054.        System.out.println("Mode OFF: " + (end - start));
    055.    }
    056. 
    057.    private void runMultipleTimesWithModeOff(Reader reader) throws ScriptException {
    058.        ScriptEngineManager manager = new ScriptEngineManager();
    059.        ScriptEngine engine = manager.getEngineByName("jruby");
    060.        engine.eval(reader);
    061.        CompiledScript cs = ((Compilable)engine).compile(reader);
    062.        long start = Calendar.getInstance().getTimeInMillis();
    063.        for (int i=0; i<iteration; i++) {
    064.            cs.eval();
    065.        }
    066.        long end = Calendar.getInstance().getTimeInMillis();
    067.        System.out.println("Mode OFF (" + iteration + " times): " + (end - start));
    068.    }
    069. 
    070.    private void runWithCompileModeJit(Reader reader) throws ScriptException {
    071.        System.setProperty("org.jruby.embed.compilemode", "jit");
    072.        ScriptEngineManager manager = new ScriptEngineManager();
    073.        ScriptEngine engine = manager.getEngineByName("jruby");
    074.        engine.eval(reader);
    075.        long start = Calendar.getInstance().getTimeInMillis();
    076.        engine.eval(reader);
    077.        long end = Calendar.getInstance().getTimeInMillis();
    078.        System.out.println("Mode JIT: " + (end - start));
    079.    }
    080. 
    081.    private void runMultipleTimesWithModeJit(Reader reader) throws ScriptException {
    082.        System.setProperty("org.jruby.embed.compilemode", "jit");
    083.        ScriptEngineManager manager = new ScriptEngineManager();
    084.        ScriptEngine engine = manager.getEngineByName("jruby");
    085.        engine.eval(reader);
    086.        CompiledScript cs = ((Compilable)engine).compile(reader);
    087.        long start = Calendar.getInstance().getTimeInMillis();
    088.        for (int i=0; i<iteration; i++) {
    089.            cs.eval();
    090.        }
    091.        long end = Calendar.getInstance().getTimeInMillis();
    092.        System.out.println("Mode JIT (" + iteration + " times): " + (end - start));
    093.    }
    094. 
    095.    private void runWithCompileModeForce(Reader reader) throws ScriptException {
    096.        System.setProperty("org.jruby.embed.compilemode", "force");
    097.        ScriptEngineManager manager = new ScriptEngineManager();
    098.        ScriptEngine engine = manager.getEngineByName("jruby");
    099.        engine.eval(reader);
    100.        long start = Calendar.getInstance().getTimeInMillis();
    101.        engine.eval(reader);
    102.        long end = Calendar.getInstance().getTimeInMillis();
    103.        System.out.println("Mode FORCE: " + (end - start));
    104.    }
    105. 
    106.    private void runMultipleTimesWithModeForce(Reader reader) throws ScriptException {
    107.        System.setProperty("org.jruby.embed.compilemode", "force");
    108.        ScriptEngineManager manager = new ScriptEngineManager();
    109.        ScriptEngine engine = manager.getEngineByName("jruby");
    110.        engine.eval(reader);
    111.        CompiledScript cs = ((Compilable)engine).compile(reader);
    112.        long start = Calendar.getInstance().getTimeInMillis();
    113.        for (int i=0; i<iteration; i++) {
    114.            cs.eval();
    115.        }
    116.        long end = Calendar.getInstance().getTimeInMillis();
    117.        System.out.println("Mode FORCE (" + iteration + " times): " + (end - start));
    118.    }
    119. 
    120.    public static void main(String[] args) throws ScriptException, FileNotFoundException {
    121.        new CompiledModeSample();
    122.    }
    123.}
    Output
    [redbridge.CompiledModeSample]
    ............................................................................
    --------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    Tests: 76. (Ok: 76; Failed: 0)
    Mode OFF: 17
    Mode FORCE: 6
    Mode JIT: 5
    Mode OFF (50 times): 221
    Mode FORCE (50 times): 67
    Mode JIT (50 times): 51
    

    References

  • 相关阅读:
    Mysql安装
    mysql 密码过期
    svn 合并分支
    idea 分支主干管理
    linux删除数据恢复,extundelete
    linux 转换文件编码
    sina 接口 根据ip获取各个国家和地区
    SQL中char、varchar、nvarchar的区别
    C#中virtual和abstract区别,举例子
    父类和子类的关系、代码例子
  • 原文地址:https://www.cnblogs.com/lexus/p/2358863.html
Copyright © 2020-2023  润新知