Scripts are gaining in popularity with developers because they are easy to write, take less time to write than compiled programs, and require little maintenance. Although hundreds of scripting languages are in use today, developers continue to create new ones because each language is geared to a particular purpose or domain space. For example, the JavaScript programming language is commonly used for web-based user interface (UI) development, and Perl is popular on the server side.
The Ruby programming language was released to the public in 1995 and gained widespread adoption in 2006. A multipurpose language that focuses on simplicity and productivity, it combines the best features of many compiled and interpreted languages, such as easy development of large programs, rapid prototyping, almost-real-time development, and compact code. Ruby is a reflective, dynamic, and interpreted object-oriented scripting language, and JRuby is a Java programming language implementation of the Ruby language syntax, core libraries, and standard libraries.
With JRuby, you get all of the advantages of Ruby plus interoperability with Java platform applications (Java applications) and access to the full range of Java platform functionality. JRuby and the Java platform are a compelling combination that you can apply to any programming situation. For example, from a JRuby script, you can call the Java platform Math library to access its powerful computational capabilities or call the Java platform Swing library to display a dialog box that requires end-user input before allowing the script to proceed. Also, you can use the JSR 223 Scripting APIs or the Bean Scripting Framework (BSF) APIs to call a JRuby script from within a Java application to, for example, invoke back-end processing scripts from a servlet to update or generate web content.
This introductory article gets you started using JRuby and the Java platform. It shows you how to set up JRuby, explains the basics of using JRuby scripts with Java applications and the NetBeans integrated development environment (NetBeans IDE), and provides links to where you can learn more. Also, the Getting Started section briefly introduces RubyGems and Ruby on Rails.
Contents
Get the latest JRuby build from the download section of the JRuby site, where both source and binary bundles are available. Download and install the binary bundle if you just want to learn JRuby and run scripts. If you want to customize the code and participate in the open-source community, download and install the source bundle. In either case, be sure to read and comply with the licensing terms.
The examples in this article are written to the JRuby 0.9.8 binary release. JRuby requires Java Development Kit (JDK) 1.4 or later, but you need JDK 6 software if you want to run the examples that use the JSR 223 Scripting APIs to invoke a JRuby script from a Java application. See the section Executing JRuby Code From Within a Java Application for more information.
Once you have installed the software, you can run JRuby
interactively or invoke scripts in files. As a quick test that
everything is working, start interactive Ruby by typing
jirb
at the command line. The interactive Ruby prompt
appears shortly: irb(main):003:0
, where you can test the
puts
command as shown. Note that => nil
is
returned by the puts
command and means that the return value
is nil.
sr1-usca-08 jirb irb(main):003:0> puts "Hi There!" Hi There! => nil irb(main):004:0>
If you put the puts
line into the
myprog.rb
file, you can run it like this:
sr1-usca-08 jruby myprog.rb Hi There! sr1-usca-08
The JRuby installation includes documentation, examples, and
sample programs to help you get started. The /jruby-0.9.8/lib/
directory and its subdirectories provide built-in
and standard libraries for you to use in your JRuby programs, as well as
support for RubyGems.
RubyGems
RubyGems is software for managing third-party programs and
libraries. You use the /jruby-0.9.8/bin/gem
command to
manage RubyGems. You can learn more about RubyGems from the RubyGems
User Guide. This article's For More Information
section also has a list of free tutorials and articles for learning
Ruby syntax.
Ruby on Rails
Ruby on Rails is a software package that works with a database and a web server for rapidly developing database-backed web applications that follow the model-view-controller (MVC) design pattern. You can use JRuby on Rails with Netbeans IDE or by using RubyGems to install Rails into your JRuby installation as explained in the JRuby on Rails site.
You can call standard Java platform APIs, third-party Java platform APIs, or both
from interactive Ruby (jirb
) or a JRuby script
by either putting the Java archive (JAR) files in the
$RUBY_HOME/lib
directory or modifying the CLASSPATH
environment variable, and then using the require
keyword in your
program to include the libraries.
Code Example 1: Third-Party Library and Code Snippet
Code Example 1 shows how to use the require
keyword to reference
or include both third-party and Java platform API libraries.
#Load Java platform and third-party API support using JRuby 0.9.1 and later syntax require 'java' require 'xml-apis-1.3.02.jar' #Third-party code ... org.w3c.dom.Element root = g.getRoot() svgdocument = impl.createDocument(svgNS, "svg", null) org.w3c.dom.Node node = svgdocument.importNode(root, true) ...
Code Example 2: Java Platform API Libraries and Example Swing Program
Code Example 2 takes a very simple SwingUI.java
application and
converts it to the JRuby naming conventions and syntax shown.
Some
usages, such as not terminating statements with semicolons
(;
) and prefixing variables with underscores
(_
), are optional. Other usages, such as using a dollar
sign ($
) to declare global variables or double colons
(::
) to reference constants, are required.
Also, notice the scriptlike structure with the def
and end
keywords instead of curly braces ({
and }
).
Although curly braces work for closures, they do not work in other
places, and the scriptlike syntax is more readable and easier to
debug. The new
operator is a method call to instantiate
a class, for example,
$_button.addActionListener(Click.new())
instead of
button.addActionListener(this);
.
The JRuby code is shorter, and its class declarations are simplified. It has no constructor, and the code to completely exit the application in the JRuby line
_frame.defaultCloseOperation = JFrame::EXIT_ON_CLOSE
replaces the more involved WindowListener
lines in
the main
method. In fact, the JRuby version has no
main
method at all.
Figure 1 shows what the simple program looks like when it executes, and Figure 2
shows what it looks like after you click the Click Me button.
Figure 1: Example program at startup
Figure 2: Example program after button click
#Load Java platform support using JRuby 0.9.1 and later syntax require 'java' JFrame = javax.swing.JFrame JLabel = javax.swing.JLabel JPanel = javax.swing.JPanel JButton = javax.swing.JButton BorderLayout = java.awt.BorderLayout Event = java.awt.event java.lang.boolean $_clickMeMode = true _frame = JFrame.new() _panel = JPanel.new() _panel.setLayout(BorderLayout.new()) _panel.setBackground(java.awt.Color::white) _frame.getContentPane().add(_panel) _frame.defaultCloseOperation = JFrame::EXIT_ON_CLOSE $_button = JButton.new("Click Me") $_text = JLabel.new("I'm a Simple Program") _panel.add(BorderLayout::CENTER, $_text) _panel.add(BorderLayout::SOUTH, $_button) class Click < java.awt.event.ActionListener def actionPerformed(event) java.lang.Object source = event.getSource() if (source == $_button) if ($_clickMeMode) $_text.setText("Button Clicked") $_button.setText("Click Again") $_clickMeMode = false else $_text.setText("I'm a Simple Program") $_button.setText("Click Me") $_clickMeMode = true end end end end $_button.addActionListener(Click.new()) _frame.setTitle("Example") _frame.pack() _frame.setVisible(true)
JSR 223, Scripting for the Java Platform, provides an API framework for calling scripting code from within a Java application and passing data between the application and the script. These features make it possible to combine existing scripts with Java applications and to extend a Java application with general-purpose scripts that other Java applications can also use.
JSR 223 Scripting APIs are available in JDK 6 software, and by default, the APIs support the JavaScript programming language. With a little setup as described in the section JRuby Scripting Engine Setup, you can use the JSR 223 Scripting APIs with any JSR 223-compliant scripting engine such as JRuby.
The Bean Scripting Framework (BSF), discussed later in this article, is another way to call scripting code from within a Java application. Although inspired by BSF, JSR 223 adds additional features such as more flexible global variable handling, multiple global scopes, and the ability to generate simple scripts.
Code Example 3: Using JSR 223 Scripting APIs to Invoke JavaScript Technology Code
The Java Platform Scripting Programmer's Guide explains how to use JSR 223 Scripting APIs with the JavaScript programming language. Code Example 3 is the first example in the programming guide, and Code Example 4 is the equivalent program modified to call JRuby scripting code.
import javax.script.*; public class EvalScript { public static void main(String[] args) throws Exception { // Create a script engine manager. ScriptEngineManager factory = new ScriptEngineManager(); // Create a JavaScript technology engine. ScriptEngine engine = factory.getEngineByName("JavaScript"); // Evaluate JavaScript technology code from string. try { engine.eval("print('Hello')"); } catch (ScriptException exception) { exception.printStackTrace(); } } }
Code Example 4: Using JSR 223 Scripting APIs to Invoke JRuby Code
This is the code from Code Example 3 converted to use JRuby. The code is almost identical except for minor modifications on two lines. See also the article Scripting for the Java Platform for more information on the JSR 223 Scripting APIs in JDK 6 software.
import javax.script.*; public class EvalScript { public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager(); // Create a JRuby engine. ScriptEngine engine = factory.getEngineByName("jruby"); // Evaluate JRuby code from string. try { engine.eval("puts('Hello')"); } catch (ScriptException exception) { exception.printStackTrace(); } } }
JRuby Scripting Engine Setup
At runtime, the JSR 223 Scripting APIs must locate the appropriate script engine
for the scripting language you want to use. The script engine interprets
and executes the script. You can get the current JSR 223
third-party script engines from the
Scripting Project
on java.net by downloading the
jsr223-engines.tar.gz
or the
jsr223-engines
file and expanding it somewhere on your system, for
example, in the scriptengines
directory.
The scriptengines
directory contains a directory for each JSR 223 script
engine in the project, so you can see all the engines that are currently supported.
The build
directory for each script engine contains a JAR file
with the script engine classes. In the case of JRuby, the script engine JAR file
is jruby-engine.jar
. Each script engine also has a lib
directory where you copy engine-specific JAR file libraries. To use the JRuby
engine, copy the asm-2.2.3.jar
and jruby.jar
files from
your JRuby installation's lib
directory into the JRuby script engine's
lib
directory, as shown in Figure 3.
Figure 3: Move the JAR files
Note: You could leave thejruby.jar
andasm-2.2.3.jar
files under the JRuby installation and adjust the-cp
option to thejava
interpreter command shown in the Compile and Run section accordingly. However, moving the files makes it possible to run the JRuby engine interactively without editing thejruby.bat
orjruby.sh
scripts in the script engine'sbin
directory.
Compile and Run
Code Example 4 compiles with the JDK 6 software's
javac
command, but in order for the JSR 223 Scripting
APIs to find the JRuby classes it needs at runtime, you must use the
-cp
option with the java
command as shown
here to reference the JAR files.
Here is the Windows system syntax:
D:\scriptengines\jruby>java -cp .; D:\scriptengines\jruby\build\jruby-engine.jar; D:\scriptengines\jruby\lib\asm-2.2.3.jar; D:\scriptengines\jruby\lib\jruby.jar EvalScript
The UNIX syntax follows:
java -cp .: /scriptengines/jruby/lib/asm-2.2.3.jar: /scriptengines/jruby/build/jruby-engine.jar: /scriptengines/jruby/lib/jruby.jar EvalScript
JRuby comes with Bean Scripting Framework (BSF) support in the bsf.jar
file located in the JRuby lib
directory. BSF, which is part of the
Apache
Jakarta open-source project, enables the use of scripting languages
within a Java application. BSF supports a wide range of scripting languages, including JRuby.
See the
BSF API documentation for more information on the BSF APIs.
Code Example 5: Using BSF to Invoke JRuby Code
Code Example 5 takes Code Example 4 and adapts it to use the BSF APIs.
import org.apache.bsf.*; public class BSF { public static void main(String[] args) throws Exception { // Create a script manager. BSFManager bsfmanager=new BSFManager(); // Evaluate the ruby expression. try { bsfmanager.eval("ruby","Test",0,0,"puts('Hello')"); } catch (BSFException exception) { exception.printStackTrace(); } }
Table 1: Parameters to the eval
method.
Type | Value | Definition |
---|---|---|
java.lang.String |
ruby |
Language identifier. Both Ruby and JRuby are specified by the string
ruby . The classpath points to either the
Ruby or JRuby JAR file. |
java.lang.String |
Test |
Source of this expression such as the name of the file containing the script. In this case, a dummy value is supplied. |
int |
0,0 |
Row and column values to pinpoint the error location in the source script. |
java.lang.Object |
puts('Hello')") |
JRuby expression to be evaluated. |
Compile and Run
Code Example 5 compiles with the JDK 6 software javac
and java
commands, but in order for the BSF APIs to find
the JRuby classes that the code example needs at both compile and
runtime, use the -cp
option as shown here to reference
the JAR files.
Here is the Windows system syntax:
D:javac -cp .; D:\home\yourdirectory\jruby-0.9.8\lib\bsf.jar: D:\home\yourdirectory\jruby-0.9.8\lib\jruby.jar BSF.java D:java -cp .: D:\home\yourdirectory\jruby-0.9.8\lib\bsf.jar: D:\home\yourdirectory\jruby-0.9.8\lib\jruby.jar BSF
The UNIX syntax follows:
javac -cp .: /home/yourdirectory/jruby-0.9.8/lib/bsf.jar: /home/yourdirectory/jruby-0.9.8/lib/jruby.jar BSF.java java -cp .: /home/yourdirectory/jruby-0.9.8/lib/bsf.jar: /home/yourdirectory/jruby-0.9.8/lib/jruby.jar BSF
The NetBeans IDE supports Java applications that use JSR 223 Scripting APIs and pure JRuby and Ruby development. It also provides RubyGems and Ruby on Rails functionality. At the time of this writing, you can get Ruby and JRuby support with the NetBeans IDE in either of the following two ways.
Once setup is complete, you can run Code Examples 3, 4, and 5 in
the NetBeans IDE by creating a project for each example and adding
the appropriate JAR files to the Libraries tree in each project.
Also, at the time of this writing, the easiest way to run Code
Example 2 in the NetBeans IDE is to download the NetBeans IDE 6.0 for
Windows PC, create a new Ruby project, copy the JRuby code for Code
Example 2 into main.rb
, and run the project.
Using the NetBeans IDE provides a number of time-saving advantages including code completion, escape codes within literal strings and regular expressions, integrated documentation pop-up windows for Ruby API calls, semantic analysis with highlighting of parameters and unused local variables, and occurrence highlighting. See NetBeans IDE 6.0 Preview (M9) Information for details.
You can use JSR 223 and JRuby with a Java application to decouple compiled code from scripting functions to simplify updates, changes, and maintenance. The advantages to structuring an application to call JRuby functions are as follows:
Code Example 6: Data Input and Output With JSR 223 and JRuby
FileIO.java
is a simple data
input and output application that illustrates how to use JSR 223
Scripting APIs to execute scripts from within a Java application.
FileIO prompts the user for a text string, stores the text string to
a file, reads the text string from the file, and displays it to the
user. It uses JSR 223 Scripting APIs to call
connectivity.rb
, which is a JRuby script that contains
read
and write
functions to handle data
input and output for the application.
Figure 4 shows what the simple data input and output program looks like before user-entered text is written to the file. Figure 5 shows the same program after it reads the saved text back out of the file.
Figure 4: Example program at startup
Figure 5: Example program after button click
JRuby Functions
These are the two JRuby functions in the
connectivity.rb
file. The f1
and
f2
variables are handles for accessing the
text.txt
file.
#Read lines from file text.txt def read File.open('text.txt', 'r') do |f1| while line = f1.gets return line end end end #Write data to file text.txt def write(data) File.open('text.txt', 'w') do |f2| f2.puts data end end
Java Application With JSR 223 Scripting APIs
The JSR 223 Scripting APIs are used in the application's
actionPerformed
method, and the relevant parts of that
method are shown here. To compile and run the full example, use the
steps for Code Example 4, but substitute the correct application file
name.
The example uses Invocable
, which is an optional
interface that enables a Java application to invoke a specific script
function or script method. The JRuby and JavaScript engines implement
this interface, but if you want to use a different scripting
language, check that this interface is implemented for it.
The example opens a file reader on the
connectivity.rb
file, which contains the
read
and write
JRuby functions. The
engine.eval(f);
line executes the script and
ScriptException
is thrown if there is a problem in the
script.
The inv.invokeFunction("write", text);
line calls the
write
function in the connectivity.rb
file
and passes it the text
parameter. The next line calls
the read
function and returns the data to be displayed
in the application.
public void actionPerformed(ActionEvent event){ ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("jruby"); // Enable the JRuby script engine to invoke a script in a file. Invocable inv = (Invocable) engine; Object obj = null; try { // Open a file reader on the external JRuby script file. FileReader f = new FileReader("connectivity.rb"); // Evaluate (execute) the script. Once evaluated, any functions // in the script can be called with the invokeFunction method. engine.eval(f); // This error is thrown when there is a problem in the script. } catch (javax.script.ScriptException e) { System.out.println("Script Exception"); } catch(java.io.FileNotFoundException e) { System.out.println("Cannot write to text.txt"); e.printStackTrace(); } Object source = event.getSource(); if (source == button) { if (_clickMeMode){ try { // Get application data. Object text = textField.getText(); // Invoke write function with text parameter. inv.invokeFunction("write", text); // Invoke read function and get the return value. obj = inv.invokeFunction("read"); } catch (javax.script.ScriptException e) { System.out.println("Script Exception"); String mess = e.getMessage(); System.out.println(mess); } catch (java.lang.NoSuchMethodException e) { System.out.println("No such method"); e.printStackTrace(); } // Display data returned from function. textField.setText(""); text.setText("Text retrieved from file:"); if(obj.toString() == null) { String empty = null; textField.setText(empty); } else { String s = obj.toString(); textField.setText(s); } ... } } }
JRuby combines the convenience of scripting with the power of the Java platform. The JSR 223 Scripting APIs make it possible to easily extend applications with scripts, create modular applications that use scripts, and share data among applications and scripts. Scripts provide speed, convenience, and flexibility to any software development effort. Although scripting code is generally slower than a compiled program the first time it executes, but subsequently compares to a compiled program. As technology advances and computers get faster, the initial speed of scripting code will improve dramatically.
© 1994-2005 Sun Microsystems, Inc.