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

原文地址:https://www.cnblogs.com/lexus/p/2358863.html