Getting Started
From JRubyWiki
Contents |
Installing JRuby
- Either download and expand a JRuby archive from http://dist.codehaus.org/jruby or build it from the source. Building JRuby from source is very easy, see the instructions #Downloading_Source_and_Building_Yourself further down this page.
Basics of Getting JRuby Running
How to configure your environment:
- Make sure that the environment variable $JAVA_HOME (or %JAVA_HOME% on Windows) is set to point to the version of Java installed on your system that you want to use with JRuby.
- Add JRuby's bin directory to your $PATH (or %PATH% on Windows) environment variable. This is an optional step. You might omit it, but then you have to specify a full path to the jruby script every time.
- If you already have another version of Ruby installed installed add JRuby's bin directory to the end of the PATH environmental variable.
For example, once you've downloaded or built a JRuby install and it is located in the directory:
/opt/jruby
the shell and batch scripts: jruby and jruby.bat will be located in the directory:
/opt/jruby/bin
So you'll need to add /opt/jruby/bin to your $PATH.
Once it's done, invoke the following command to verify the installation:
jruby -v
Invoking system-level executable commands
The recommended way to invoke system-level executable commands (these are commands installed into the JRuby bin/ directory, e.g., rake, rails, etc) in JRuby is to always execute them via jruby -S:
jruby -S gem list --local jruby -S gem install rails mongrel jdbc-mysql activerecord-jdbcmysql-adapter jruby -S rails blog jruby -S rake -T jruby -S rake db:migrate
The -S parameter to JRuby tells JRuby to look for the script in its bin/ directory.
Executing scripts
Examples of running any other Ruby script in JRuby (these are any Ruby scripts not installed into the JRuby's bin/ directory):
jruby script/server jruby my_ruby_script.rb
Ruby Interactive Console
One of the few (perhaps only) standard Ruby utility that has a different name in JRuby than in C Ruby is the command for the interactive Ruby console: jirb. In C Ruby this utility is called just: irb.
Installing and using Gems in JRuby
The RubyGems can be easily installed with JRuby as follows:
jruby -S gem install rails mongrel jdbc-mysql activerecord-jdbcmysql-adapter
Many Gems will work fine in JRuby, however some Gems build native C libraries as part of their install process. These Gems will not work in JRuby unless the Gem has also provided a Java equivalent to the native library.
Mongrel and Hpricot are two examples of Gems that build their native library in a platform independent manner. Each of them specify a parsing library using the Ragel language and a Ragel program can be automatically converted into either C or Java as part of the compile process.
Also, keep in mind that installing gems from behind a firewall will require setting the HTTP_PROXY (format http://${http-proxy-host}:${http-proxy-port}/)
See also Troubleshooting.
JRuby Command Parameters
$ jruby --help
Usage: jruby [switches] [--] [programfile] [arguments]
-0[octal] specify record separator (, if no argument)
-a autosplit mode with -n or -p (splits $_ into $F)
-b benchmark mode, times the script execution
-c check syntax only
-Cdirectory cd to directory, before executing your script
-d set debugging flags (set $DEBUG to true)
-e 'command' one line of script. Several -e's allowed. Omit [programfile]
-Fpattern split() pattern for autosplit (-a)
-Idirectory specify $LOAD_PATH directory (may be used more than once)
-J[java option] pass an option on to the JVM (e.g. -J-Xmx512m)
use --properties to list JRuby properties
-Kkcode specifies KANJI (Japanese) code-set
-l enable line ending processing
-n assume 'while gets(); ... end' loop around your script
-p assume loop like -n but print line also like sed
-rlibrary require the library, before executing your script
-S look for the script in bin or using PATH environment variable
-T[level] turn on tainting checks
-v print version number, then turn on verbose mode
-w turn warnings on for your script
-W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)
-X[option] enable extended option (omit option to list)
--copyright print the copyright
--properties List all configuration Java properties (pass -J-Dproperty=value)
--version print the version
Downloading Source and Building Yourself
The JRuby source code is available in a Subversion repository here: http://svn.codehaus.org/jruby/trunk/jruby
Retrieve the trunk version of the JRuby source and build JRuby using the following shell commands (Note: Ant 1.7 is required to build JRuby version greater than 1.1):
svn co http://svn.codehaus.org/jruby/trunk/jruby jruby ant
Create an up-to-date version of jruby-complete.jar with this ant task:
ant jar-complete
Generate an up-to-date set of the JavaDoc for JRuby located here: docs/api/index.html:
ant create-apidocs
Delete any build and compile artifacts:
ant clean
Run the JRuby tests:
ant test
Retrieve revision 6130 of the JRuby source:
svn co -r 6130 http://svn.codehaus.org/jruby/trunk/jruby jruby
You can easily automate all of this and more into a single script, see: http://pastie.caboo.se/165048.
Benchmarking
The current popular way to benchmark JRuby performance is to perform a gem installation of Rake. The install process exercises a number of APIs and represents a fairly general-purpose application of Ruby. It's also extremely interpreter-heavy.
After getting a build of JRuby, as above, the following steps can be used to benchmark JRuby using Gem and Rake:
- Fetch the current Rake gem from RubyForge
- Execute the following command (putting JRUBY_HOME/bin in your path or referencing it directly):
JRUBY_HOME/bin/gem install <rake gem file>
- By preceding this command line with the unix "time" command you can test end-to-end performance. Of course there are other ways to wire in profiling and performance-monitoring tools that won't be detailed here.
A sample run from a MacBook Pro under Apple's Java 6 JVM is shown below:
Nutters-Computer:~/Documents/workspace/jruby headius$ time bin/gem install rake-0.7.1.gem Successfully installed rake, version 0.7.1 Installing ri documentation for rake-0.7.1... Installing RDoc documentation for rake-0.7.1... real 0m52.596s user 0m51.740s sys 0m2.146s
Example code
Below is some example code of calling ruby from within java and java from ruby
Ruby: call_java.rb
require "java"
include_class "java.util.TreeSet"
include_class "com.example.CallMe"
include_class "com.example.ISpeaker"
puts "Hello from ruby"
set = TreeSet.new
set.add "foo"
set.add "Bar"
set.add "baz"
set.each { |v| puts "value: #{v}" }
cm = CallMe.new
cm.hello
$globalCM.hello
class CallJava
include ISpeaker
def initialize
super
@count = 0
end
def say(msg)
puts "Ruby saying #{msg}"
end
def addOne(from)
# m.synchronize {
@count += 1
puts "Now got #@count from #{from}"
# }
end
end
Java: ISpeaker.java
package com.example;
public interface ISpeaker {
public void say(String msg);
public void addOne(String from);
}
Java: CallMe.java
package com.example;
public class CallMe {
String mName;
public CallMe() {
this("Default");
}
public CallMe(String name) {
mName = name;
}
public void hello() {
System.out.println("Hello from "+mName);
}
public static void main(String []args) {
System.out.println("Called main");
}
}
Java: CallRuby.java
package com.example;
import org.apache.bsf.BSFManager;
import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;
import java.io.FileReader;
import java.io.IOException;
/**
* Example of how to:
* 1. Use java objects in ruby
* 2. Subclass/implement java objects in ruby
* 3. Get ruby objects for use in java world
* 4. Proxy ruby objects for normal use as java objects (interfaces/class)
*/
public class CallRuby {
public static void main(String[] args) throws Exception {
String dir = "/dclark/workspace/jrubytest/ruby/";
double[] deltas = new double[3];
for (int i = 0; i < 3; i++) {
boolean useBSF = (i == 0);
long start = System.currentTimeMillis();
if (useBSF) {
//--- Initialise ruby
BSFManager.registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[]{"rb"});
BSFManager manager = new BSFManager();
//--- Define a global variable
CallMe javaCallMe = new CallMe("globalCallMeInJava");
manager.declareBean("globalCM", javaCallMe, javaCallMe.getClass());
//--- Load a ruby file
manager.exec("ruby", "call_java.rb", -1, -1, getFileContents(dir + "call_java.rb"));
//--- Make a new ruby object
String expr = "CallJava.new";
ISpeaker ruby = (ISpeaker) manager.eval("ruby", "call_java.rb", -1, -1, expr);
testMultiThreadsCallingRubyObject(ruby);
} else {
//--- Initialise ruby
final Ruby runtime = Ruby.getDefaultInstance();
// Need the blank object so can get a nice runtime for the Java.staticMethods calls
runtime.eval(runtime.parse("require \"java\"\nclass BlankForJva\nend\n", "BlankForJva.rb", runtime.getCurrentContext().getCurrentScope(), 0));
final IRubyObject blankRuby = runtime.evalScript("BlankForJva.new");
//--- Define a global variable
CallMe javaCallMe = new CallMe("globalCallMeInJava");
IRubyObject globValue = JavaUtil.convertJavaToRuby(runtime, javaCallMe);
// Wrap so that all methods are visible to ruby
globValue = Java.java_to_ruby(blankRuby, globValue, Block.NULL_BLOCK);
GlobalVariable globVar = new GlobalVariable(runtime, "$globalCM", globValue);
runtime.defineVariable(globVar);
//--- Load a ruby file
runtime.eval(runtime.parse(getFileContents(dir + "call_java.rb"), "call_java.rb", runtime.getCurrentContext().getCurrentScope(), 0));
//--- Make a new ruby object
String expr = "CallJava.new";
final IRubyObject rawRuby = runtime.evalScript(expr);
ISpeaker ruby;
if (i == 1) {
// Standard wrapper using Java Proxies
ruby = (ISpeaker) JavaEmbedUtils.rubyToJava(runtime, rawRuby, ISpeaker.class);
} else {
// Or manually wrap ruby object so can be used as the interface (can optionally add synchronization as required on methods)
ruby = new ISpeaker() {
public void addOne(String from) {
// synchronized (rawRuby) {
rawRuby.callMethod(runtime.getCurrentContext(), "addOne", JavaUtil.convertJavaToRuby(runtime, from));
// }
}
public void say(String msg) {
rawRuby.callMethod(runtime.getCurrentContext(), "say", JavaUtil.convertJavaToRuby(runtime, msg));
}
};
}
testMultiThreadsCallingRubyObject(ruby);
}
long end = System.currentTimeMillis();
deltas[i] = (end - start) / 1000.0;
}
for (int i = 0; i < deltas.length; i++) {
System.out.println("Took " + deltas[i] + " on pass " + i);
}
}
private static String getFileContents(String filename) throws IOException {
FileReader in = new FileReader(filename);
return IOUtils.getStringFromReader(in);
}
public static void testMultiThreadsCallingRubyObject(final ISpeaker ruby) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
ruby.addOne("t1");
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
ruby.addOne("t2");
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
ruby.addOne("end");
}
}
Note that if you only have simple interface requirements then you can use the second method of proxying the ruby object to include method level synchronization.
Note that BSF calling does not preserve ruby stack traces (add an error to a script and run both ways using the code above).
Also, note that the times you get from running this example are interesting (on my old Windows box using Java5):
Took 5.469 on pass 0 // This is the Standard BSF Wrapping Took 1.75 on pass 1 // Using normal Java Proxies Took 1.359 on pass 2 // Rolling your own redirector class to call Ruby

