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.
Contents [hide]
- 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:
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 singletonA 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 globalRedBrdige 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 forceExperimental 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:
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
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.
}
Output01.
# 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
Eval with Bindings
A constant, PI, is injected Ruby by Java.
Output01.
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.
}
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.
}
Output01.
# 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
Eval with ScriptContext
Output01.
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.
}
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.
}
Output01.
#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
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
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
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
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
Output01.
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.
}
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))
Output01.
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.
}
Compile(not just parsing, real compilation) Mode
Output001.
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.
}
References