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.
- 1 RedBridge Wiki
- 2 Download
- 3 Configurations
- 3.1 Class Path
- 3.2 Context Instance Model
- 3.3 Local Variable Behavior
- 3.4 CompileMode
- 3.5 Line Number
- 4 ScriptEngineManager for JRuby
- 5 Code Examples
- 5.1 Simple Eval
- 5.2 Simple Eval 2
- 5.3 Eval with Bindings
- 5.4 Eval with Bindings 2
- 5.5 Eval with ScriptContext
- 5.6 Eval with ScriptContext 2
- 5.7 Parse Once, Eval Many Times
- 5.8 Java Interface Implementation
- 5.9 Java Interface Implementation 2
- 5.10 Method Invocation: invokeFunction
- 5.11 Method Invocation2: invokeMethod
- 5.12 Compile(not just parsing, real compilation) Mode
- 6 References
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:
String classPath = "/Users/yoko/Tools/jruby-1.3.1/lib/ruby/1.8";
System.setProperty("org.jruby.embed.class.path", classPath);
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localcontext.scope", "threadsafe");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localcontext.scope", "singleton");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localvariable.behavior", "transient");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localvariable.behavior", "persistent");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.localvariable.behavior", "global");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
System.setProperty("org.jruby.embed.compilemode", "jit");
ScriptEngineManager manager = new ScriptEngineManager();
// for OS X users
//JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
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:
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.jruby.embed.jsr223.JRubyScriptEngineManager;
public class LineNumberSample {
private final String script =
"puts \"Hello World.\"\n" +
"puts \"Error is here.";
private LineNumberSample() throws ScriptException {
JRubyScriptEngineManager manager = new JRubyScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
try {
engine.eval(script); // Since no line number is given, 0 is applied to.
} catch (Exception e) {
;
}
try {
engine.getContext().setAttribute("org.jruby.embed.linenumber", 1, ScriptContext.ENGINE_SCOPE);
engine.eval(script);
} catch (Exception e) {
;
}
try {
engine.getContext().setAttribute("org.jruby.embed.linenumber", 2, ScriptContext.ENGINE_SCOPE);
engine.eval(script);
} catch (Exception e) {
;
}
}
public static void main(String[] args)
throws ScriptException {
new LineNumberSample();
}
}
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:
JRubyScriptEngineManager manager = new JRubyScriptEngineManager(Thread.currentThread().getContextClassLoader());
ScriptEngine engine = manager.getEngineByName("jruby");
Code Examples
Simple Eval
package redbridge;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvalStringSample {
private EvalStringSample() throws ScriptException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
System.setProperty("org.jruby.embed.localvariable.behavior", "persistent");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval("p=9.0");
engine.eval("q = Math.sqrt p");
engine.eval("puts \"square root of #{p} is #{q}\"");
System.out.println("q = " + engine.get("q"));
}
public static void main(String[] args) throws ScriptException {
new EvalStringSample();
}
}
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
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvalReaderSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private EvalReaderSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/calendar.rb";
Reader reader = new FileReader(filename);
Object result = engine.eval(reader);
System.out.println("Next year is " + result + ".");
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new EvalReaderSample();
}
}
# calendar.rb [Birch]
require 'date'
class Calendar
def initialize
@today = DateTime.now
end
def next_year
@today.year + 1
end
end
c = Calendar.new
c.next_year
Output
[redbridge.EvalReaderSample] Next year is 2010.
Eval with Bindings
A constant, PI, is injected Ruby by Java.
package redbridge;
import java.io.FileNotFoundException;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class EvalStringBindingsSample {
private EvalStringBindingsSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String script =
"def get_perimeter(x, y)\n" +
"x + 2.0 * y + PI / 2.0 * x\n" +
"end\n" +
"get_perimeter(1.5, 1.5)";
Bindings bindings = new SimpleBindings();
bindings.put("PI", 3.1415);
Double result = (Double) engine.eval(script, bindings);
System.out.println(result.toString());
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new EvalStringBindingsSample();
}
}
Output
[redbridge.EvalStringBindingsSample] 6.8561250000000005
Eval with Bindings 2
Tow instance variables, @month and @day, are injected Ruby by Java.
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class EvalReaderBindingsSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private EvalReaderBindingsSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/count_down.rb";
Reader reader = new FileReader(filename);
Bindings bindings = new SimpleBindings();
bindings.put("@month", 1);
bindings.put("@day", 1);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
String result = (String) engine.eval(reader, bindings);
System.out.println(result.toString());
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new EvalReaderBindingsSample();
}
}
# count_down.rb [Birch]
require 'date'
def count_down_birthday
now = DateTime.now
year = now.year
days = DateTime.new(year, @month, @day).yday - now.yday
if days < 0
this_year = DateTime.new(year, 12, 31).yday - now.yday
next_year = DateTime.new(year + 1, @month, @day).yday
days = this_year + next_year
end
return "Happy Birthday!" if days == 0
return "You have #{days} day(s) to your next birthday!"
end
count_down_birthday
Output
[redbridge.EvalReaderBindingsSample] You have 210 day(s) to your next birthday!
Eval with ScriptContext
package redbridge;
import java.util.List;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
public class EvalStringScriptContextSample {
private EvalStringScriptContextSample() throws ScriptException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String script =
"def norman_window(x, y)\n" +
"return get_area(x, y), get_perimeter(x, y)\n" +
"end\n" +
"def get_area(x, y)\n" +
"x * y + Math::PI / 8.0 * x ** 2.0\n" +
"end\n" +
"def get_perimeter(x, y)\n" +
"x + 2.0 * y + Math::PI / 2.0 * x\n" +
"end\n" +
"norman_window width, height";
ScriptContext context = new SimpleScriptContext();
context.setAttribute("width", 1, ScriptContext.ENGINE_SCOPE);
context.setAttribute("height", 3, ScriptContext.ENGINE_SCOPE);
List<Double> result = (List<Double>) engine.eval(script, context);
for (int i=0; i<result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) throws ScriptException {
new EvalStringScriptContextSample();
}
}
Output
[redbridge.EvalStringScriptContextSample] :1 warning: already initialized constant STDOUT :1 warning: already initialized constant STDERR 3.392699081698724 8.570796326794897
Eval with ScriptContext 2
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.List;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
public class EvalReaderScriptContextSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private EvalReaderScriptContextSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/norman_window_dimensions2.rb";
Reader reader = new FileReader(filename);
ScriptContext context = new SimpleScriptContext();
context.setAttribute("@x", 4.0, ScriptContext.ENGINE_SCOPE);
context.setAttribute("@y", 1.0, ScriptContext.ENGINE_SCOPE);
List<Double> result = (List<Double>) engine.eval(reader, context);
for (int i=0; i<result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new EvalReaderScriptContextSample();
}
}
#norman_window_dimensions2.rb [Birch] def norman_window return get_area, get_perimeter end def get_area @x * @y + Math::PI / 8.0 * @x ** 2.0 end def get_perimeter @x + 2.0 * @y + Math::PI / 2.0 * @x end norman_windowOutput
[redbridge.EvalReaderScriptContextSample] :1 warning: already initialized constant STDOUT :1 warning: already initialized constant STDERR 10.283185307179586 12.283185307179586
Parse Once, Eval Many Times
package redbridge;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class CompileStringSample {
private CompileStringSample() throws ScriptException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String script =
"def norman_window(x, y)\n" +
"puts \"Dimensions of a #{x} x #{y} Norman window are\"\n" +
"puts \"area: #{get_area(x, y)}\"\n" +
"puts \"perimeter: #{get_perimeter(x, y)}\"\n" +
"end\n" +
"def get_area(x, y)\n" +
"x * y + Math::PI / 8.0 * x ** 2.0\n" +
"end\n" +
"def get_perimeter(x, y)\n" +
"x + 2.0 * y + Math::PI / 2.0 * x\n" +
"end\n" +
"norman_window width, height";
engine.put("width", 2);
engine.put("height", 1);
CompiledScript cs = ((Compilable)engine).compile(script);
cs.eval();
engine.put("width", 1);
engine.put("height", 2);
cs.eval();
engine.put("width", 2);
engine.put("height", 2);
cs.eval();
}
public static void main(String[] args) throws ScriptException {
new CompileStringSample();
}
}
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
package redbridge;
public interface Sphere {
double volume(double radius);
double surface_area(double radius);
}
Ruby Implementation
# sphere.rb [Birch] def volume(r) 4.0 / 3.0 * Math::PI * r ** 3.0 end def surface_area(r) 4.0 * Math::PI * r ** 2.0 end
Usage
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class GetInterfaceSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private GetInterfaceSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/sphere.rb";
Reader reader = new FileReader(filename);
engine.eval(reader);
Sphere sphere = ((Invocable)engine).getInterface(Sphere.class);
double radius = 3.0;
System.out.println("Volume of a " + radius + " radius sphere is " + sphere.volume(radius));
System.out.println("Surface area of a " + radius + " radius sphere is " + sphere.surface_area(radius));
radius = 4;
System.out.println("Volume of a " + radius + " radius sphere is " + sphere.volume(radius));
System.out.println("Surface area of a " + radius + " radius sphere is " + sphere.surface_area(radius));
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new GetInterfaceSample();
}
}
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
package redbridge;
public interface PositionFunction {
String velocity(double t);
String position(double t);
}
Ruby Implementation
# position_function.rb [Birch]
class PositionFunction
include Java::redbridge.PositionFunction
attr :v0, :s0
def initialize(v0, s0, system)
@v0 = v0
@s0 = s0
if "english" == system.downcase
@g = -32.0
@unit_v = "ft./sec"
@unit_s = "ft."
end
if "metric" == system.downcase
@g = -9.8
@unit_v = "m/sec"
@unit_s = "m"
end
end
def position(t)
"#{1.0 / 2.0 * @g * t ** 2.0 + @v0 * t + @s0} #{@unit_s}"
end
def velocity(t)
"#{@g * t + @v0} #{@unit_v}"
end
end
PositionFunction.new(initial_velocity, initial_height, system)
Usage
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class GetInterfaceWithReceiverSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private GetInterfaceWithReceiverSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/position_function.rb";
Reader reader = new FileReader(filename);
Bindings bindings = engine.createBindings();
bindings.put("initial_velocity", 30.0);
bindings.put("initial_height", 30.0);
bindings.put("system", "metric");
Object receiver = engine.eval(reader, bindings);
PositionFunction pf = ((Invocable)engine).getInterface(receiver, PositionFunction.class);
double t = 3.0;
System.out.println("Height after " + t + " sec is " + pf.position(t));
t = 1.0;
System.out.println("Velocity after " + t + " sec is " + pf.velocity(t));
reader = new FileReader(filename);
bindings = engine.createBindings();
bindings.put("initial_velocity", 30.0);
bindings.put("initial_height", 30.0);
bindings.put("system", "english");
receiver = engine.eval(reader, bindings);
pf = ((Invocable)engine).getInterface(receiver, PositionFunction.class);
t = 2.0;
System.out.println("Height after " + t + " sec is " + pf.position(t));
System.out.println("Velocity after " + t + " sec is " + pf.velocity(t));
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new GetInterfaceWithReceiverSample();
}
}
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
# count_down.rb [Birch]
require 'date'
def count_down_birthday
now = DateTime.now
year = now.year
days = DateTime.new(year, @month, @day).yday - now.yday
if days < 0
this_year = DateTime.new(year, 12, 31).yday - now.yday
next_year = DateTime.new(year + 1, @month, @day).yday
days = this_year + next_year
end
return "Happy Birthday!" if days == 0
return "You have #{days} day(s) to your next birthday!"
end
count_down_birthday
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class InvokeFunctionSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private InvokeFunctionSample() throws ScriptException, FileNotFoundException, NoSuchMethodException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/count_down.rb";
Reader reader = new FileReader(filename);
Bindings bindings = new SimpleBindings();
bindings.put("@month", 6);
bindings.put("@day", 6);
Object result = engine.eval(reader, bindings);
System.out.println(result.toString());
String method = "count_down_birthday";
bindings.put("@month", 12);
bindings.put("@day", 31);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Object[] args = null;
result = ((Invocable)engine).invokeFunction(method, args);
System.out.println(result.toString());
bindings.put("@month", 6);
bindings.put("@day", 3);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
result = ((Invocable)engine).invokeFunction(method, args);
System.out.println(result.toString());
}
public static void main(String[] args) throws ScriptException, FileNotFoundException, NoSuchMethodException {
new InvokeFunctionSample();
}
}
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
# tree_with_localvars.rb [Birch]
class Tree
attr_reader :name, :shape, :foliage, :flower
def initialize(name, shape, foliage, flower)
@name = name
@shape = shape
@foliage = foliage
@flower = flower
end
def to_s
"#{name.capitalize} is a #{shape} shaped, #{foliage} tree, and blooms #{flower.color} flowers in #{flower.bloomtime}."
end
def update(color, bloomtime)
@flower.color = color
@flower.bloomtime = bloomtime
end
end
class Flower
attr_accessor :color, :bloomtime
def initialize(color, bloomtime)
@color = color
@bloomtime = bloomtime
end
end
Tree.new(name, shape, foliage, Flower.new(color, bloomtime))
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class InvokeMethodSample {
private final static String basedir = "/Users/yoko/NetBeansProjects/Birch";
private InvokeMethodSample() throws ScriptException, FileNotFoundException, NoSuchMethodException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singlethread");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
String filename = basedir + "/src/ruby/tree_with_localvars.rb";
Reader reader = new FileReader(filename);
Bindings bindings = new SimpleBindings();
bindings.put("name", "cedar");
bindings.put("shape", "pyramidal");
bindings.put("foliage", "evergreen");
bindings.put("color", "nondescript");
bindings.put("bloomtime", "April - May");
Object receiver = engine.eval(reader, bindings);
Object[] args = null;
String result = (String) ((Invocable)engine).invokeMethod(receiver, "to_s", args);
System.out.println(result);
args = new Object[]{"pink", "March - April"};
((Invocable)engine).invokeMethod(receiver, "update", args);
bindings.put("@name", "cherry blossom");
bindings.put("@shape", "round");
bindings.put("@foliage", "deciduous");
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
args = null;
result = (String) ((Invocable)engine).invokeMethod(receiver, "to_s", args);
System.out.println(result);
}
public static void main(String[] args) throws ScriptException, FileNotFoundException, NoSuchMethodException {
new InvokeMethodSample();
}
}
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
package redbridge;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.Calendar;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class CompiledModeSample {
private final static String jrubyhome = "/Users/yoko/Tools/jruby-1.3.0";
private int iteration = 50;
private CompiledModeSample() throws ScriptException, FileNotFoundException {
System.out.println("[" + getClass().getName() + "]");
System.setProperty("org.jruby.embed.localcontext.scope", "singleton");
setLoadPaths();
String filename = jrubyhome + "/test/testEnumerator.rb";
Reader reader = new FileReader(filename);
runWithCompileModeOff(reader);
runWithCompileModeForce(reader);
runWithCompileModeJit(reader);
runMultipleTimesWithModeOff(reader);
runMultipleTimesWithModeForce(reader);
runMultipleTimesWithModeJit(reader);
}
private void setLoadPaths() {
String[] paths = {
jrubyhome + "/lib/ruby/1.8",
jrubyhome + "/lib/ruby/site_ruby/1.8",
jrubyhome
};
String separator = System.getProperty("path.separator");
String classPath = "";
for (int i=0; i < paths.length; i++) {
classPath = classPath + paths[i] + separator;
}
classPath = classPath.substring(0, classPath.length()-1);
System.setProperty("org.jruby.embed.class.path", classPath);
}
private void runWithCompileModeOff(Reader reader) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
long start = Calendar.getInstance().getTimeInMillis();
engine.eval(reader);
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode OFF: " + (end - start));
}
private void runMultipleTimesWithModeOff(Reader reader) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
CompiledScript cs = ((Compilable)engine).compile(reader);
long start = Calendar.getInstance().getTimeInMillis();
for (int i=0; i<iteration; i++) {
cs.eval();
}
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode OFF (" + iteration + " times): " + (end - start));
}
private void runWithCompileModeJit(Reader reader) throws ScriptException {
System.setProperty("org.jruby.embed.compilemode", "jit");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
long start = Calendar.getInstance().getTimeInMillis();
engine.eval(reader);
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode JIT: " + (end - start));
}
private void runMultipleTimesWithModeJit(Reader reader) throws ScriptException {
System.setProperty("org.jruby.embed.compilemode", "jit");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
CompiledScript cs = ((Compilable)engine).compile(reader);
long start = Calendar.getInstance().getTimeInMillis();
for (int i=0; i<iteration; i++) {
cs.eval();
}
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode JIT (" + iteration + " times): " + (end - start));
}
private void runWithCompileModeForce(Reader reader) throws ScriptException {
System.setProperty("org.jruby.embed.compilemode", "force");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
long start = Calendar.getInstance().getTimeInMillis();
engine.eval(reader);
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode FORCE: " + (end - start));
}
private void runMultipleTimesWithModeForce(Reader reader) throws ScriptException {
System.setProperty("org.jruby.embed.compilemode", "force");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(reader);
CompiledScript cs = ((Compilable)engine).compile(reader);
long start = Calendar.getInstance().getTimeInMillis();
for (int i=0; i<iteration; i++) {
cs.eval();
}
long end = Calendar.getInstance().getTimeInMillis();
System.out.println("Mode FORCE (" + iteration + " times): " + (end - start));
}
public static void main(String[] args) throws ScriptException, FileNotFoundException {
new CompiledModeSample();
}
}
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





