2007/11/01

alt.lang.jre: Take a shine to JRuby

alt.lang.jre: Take a shine to JRuby

Add some sparkle to your Java toolbox
developerWorks


Document options
Set printer orientation to landscape mode

Print this page
Email this page

E-mail this page


Sample code

Increase your SOA skills


Play in the IBM SOA Sandbox

Rate this page


Help us improve this content

Level: Introductory

Michael Squillace (masquill@us.ibm.com), Software Engineer, IBM
Barry Feigenbaum, Ph.D. (feigenba@us.ibm.com), Sr. Consulting IT Architect, IBM

08 Sep 2004

JRuby combines the object-oriented strength of Smalltalk, the expressiveness of Perl, and the flexibility of the Java class libraries into a single, efficient rapid development framework for the Java platform. In this third installment in the alt.lang.jre series, Michael Squillace and Barry Feigenbaum introduce JRuby, a sophisticated addition to your Java development toolbox.

JRuby is an alternate language for the Java platform. It is based on Ruby, a programming language developed by Yukihiro "Matz" Matsumoto. As stated on the RubyCentral homepage (see Resources), Ruby is a programming language that "combines the pure object-oriented power of the classic OO language Smalltalk with the expressiveness and convenience of a scripting language such as Perl." It is a relatively mature language, known for its clean, intuitive syntax and semantics and transparent, developer friendly programming model.

JRuby is a pure Java implementation of the Ruby interpreter. Like most languages discussed in this series, JRuby is both powerful and easy to learn. It incorporates the sophisticated text-processing of Perl, the iterators and closures familiar to Groovy developers, and the rapid development features of Jython and other languages discussed in this series. JRuby is also an interpreted language, so it can be run from the command line or used to evaluate simple expressions or blocks of code on the fly.

While JRuby doesn't try to be all things to all people, it certainly takes advantage of some of the milestone features found in its predecessors to form a powerful yet syntactically simple language. Unlike most languages discussed in this series, JRuby combines most of its powerful features into a single package. For example, JRuby combines iterators with text-processing features, making it relatively simple to write powerful yet intuitive parsers. It also lets us use functions as first class data types, which we can combine with blocks or closures to expand our classes to handle much of the grunt work typically left to loop constructs and more traditional iterator classes (like those found in the Java Collections framework).

About this series

While most Java technology zone readers are familiar with the Java language and how it runs on a cross-platform virtual machine, fewer may know that the Java Runtime Environment can host languages besides the Java language. This series of articles is a survey of many of the alternate languages for the JRE. Most of the languages explored here are open source and may be used for free, while a few are commercial products that must be purchased. All of the languages introduced in the alt.lang.jre series are supported by the JRE and are believed by the authors to enhance the dynamic and flexible nature of the Java platform.

Naturally, JRuby is also tightly integrated with the Java platform, incorporating the convenience and flexibility of the Java class library. Because it supports modules and classes it is well suited to scalable and robust application development. JRuby can be used to script Java classes and can also be embedded (via the interpreter) directly into Java applications. Both Ruby and JRuby are open source languages, freely available for development and deployment.

This third installment in the alt.lang.jre series is dedicated to JRuby. We'll start from the beginning, with some basic installation guidelines, then talk about what makes JRuby a worthy addition to your Java development toolbox. The rest of the article will be code driven, with examples that evolve in complexity as you learn more about the language. Download the source code for this article by clicking on the Code icon at the top or bottom of the page.

Where to get JRuby

As of this writing, you can download JRuby v0.7.0 from SourceForge. Once you've downloaded the archive, unpack it into a directory of your choosing (note that a top-level jruby-0.7.0 directory is part of the archive). The interpreter is run from the batch file on Windows platforms, or from the Bash shell script file on Unix platforms. You'll find both in JRuby's bin subdirectory. To launch JRuby simply type jruby at the OS prompt to test the interpreter.

Afterward, you should see something like the following:

using JRUBY_BASE ...
using JRUBY_HOME ...
using JAVA_HOME ...
using CLASSPATH ...
using ARGS ...


Press Ctrl-C to exit the interpreter without executing code. PressCtrl-Z to leave the interpreter and run the code you have entered.


Back to top


What makes JRuby glow

Like many other languages in this series, JRuby supports functions as first-class data types. This means functions can be assigned to variables, placed in collections, and passed to and from other functions. Also, because it is an interpreted, dynamically-typed language, JRuby is an excellent language for on-the-fly processing. Some of the more convenient features of JRuby are as follows:

* Simpler syntax: JRuby contains no statement terminator (like the semicolon in the Java language) and allows the omission of parentheses in function calls that have no arguments.

* Variables are untyped, so there is no need for declarations.

* Member attributes of classes can be specified as readable and/or writable and can be accessed by name (that is, without the use of getters and setters).

* Blocks and iterators make it easier to do repetitive evaluations, especially of collection members.

* Extensive string and regular-expression features make text-processing very simple.

All of these features (and others) together with the power of the Java platform make JRuby an excellent alternate language for the Java developer.


Back to top


Hello World!

We'll spend the remainder of this article studying and then talking about code examples. For our first example, let's see how JRuby handles the quintessential Hello World program shown below:

print "Hello, World!\n"


JRuby lets us handle this simple program in one of two ways. We can start the JRuby interpreter and enter it into the command shell followed by a Ctrl-Z to indicate end-of-file, or we can place it in a JRuby file, such as HelloWorld.rb, and execute the following command:

jruby HelloWorld.rb


As we might expect, the output is the same either way:

Hello, World!


Now that we've introduced ourselves -- Hello World! -- we can move on to the slightly more complicated program shown in Listing 1:

Listing 1. Display my public methods

x = 3
for m in x.methods
print "#{m} " if not methods.index(m)
end


About the code

The first thing to notice about the code is the methods method, which returns all of the public instance methods of the class of the object invoking it (that is, "x"), along with the methods of any superclass of the class of the object. Next, the for loop iterates through all of the methods available to the JRuby class Integer (of which the numeral 3 is an instance). If the method name appears in the methods list returned for class Object, it is not printed. As we shall see shortly, invoking any method without preceding it with an instance and the dot (.) operator invokes a method on the Object class. Hence, the methods method in the if modifier is being invoked on class Object.

You should also note that the nil value in JRuby (like null in the Java language) is equivalent to false in a conditional expression, so the test methods.index(m) == nil is the expression actually being evaluated. We use the #{...} syntax within the print call in order to print the result of evaluating the expression between the braces.

The output of this program should be a list of methods something like what we see in Listing 2:

Listing 2. Output of listing my public methods


to_str / ~ id2name ^ to_f + [] ** - >>
| to_i << & size * % integer? downto
succ next times upto step chr member? include?
sort each_with_index collect find_all inject sort_by
max entries all? select reject grep min any? partition
group_by detect map find abs -@ round zero? floor modulo
<=> ceil coerce +@ truncate remainder nonzero? divmod
> >= between? < <=



Some of the method names returned by this little program might surprise you. For instance, one method, the [] operator, returns the bit at the position specified in the subscript of the binary representation of the number. Thus, we end up with x[0] == 1, x[1] == 1, x[2] == 0, and so on. This program also returns typical arithmetic operations like + and - and conditional operators like < and >. (We'll consider other methods in this list, such as downto and step, momentarily.)


Back to top


Pure objectification

Like Groovy, JRuby treats everything as an object, whether it is a number, a string, a class, a module, a function, or even a literal. Indeed, even upon invoking the interpreter, you find yourself in the object called main. You can verify this by typing the following at the prompt:

print inspect, "\n"


The interpreter will respond with main, which is the result of invoking the print method on the result of the inspect method.

Method madness

Both the print and inspect methods are members of the Object class from which all JRuby objects inherit. (Note that this is not the same as the java.lang.Object class.) Because everything in JRuby inherits from class Object, every instance of every object has access to a large set of methods. Thus, JRuby does not have a print statement, but it may seem as if it does, since the print method is accessible everywhere. (Using print as a method rather than as a statement is, of course, familiar to Java programmers. After all, in the Java language, the print and println methods are members of the out object of the System class.)

In JRuby (like in Smalltalk) many methods provide functionality that is typically found as statements (or as keywords) in other languages. An example of this is the include_package method, which is used for importing Java packages into a program. include_package is a member method of class Module, so invoking it outside a module definition will cause an error. Hence, it is not unusual to see code like the following in a JRuby application:

module Swing
include_package 'javax.swing'
end


Literals are objects, too

Because everything (including a number or string literal) is an object in JRuby, we can write expressions like the following:

3.type
5.0.to_s # to_s is like Java's toString()
"abcde".length
[1, 2, 3].size


Such expressions will seem unusual to the Java developer, but not so to Smalltalk developers. In the Java language, for example, the Math class defines a number of public static members that perform various mathematical functions. In JRuby, this is not necessary; we don't call Math.round(3.9) as you would in the Java language; rather we use the form 3.9.round, which should be familiar to those who know Smalltalk.


Back to top


JRuby's rules

In this section we'll look at JRuby's rules for naming variables, which are reminiscent of those used in Basic. It is important to note the difference between a naming convention (such as the convention in the Java language that the name of a class begins with a capital letter) and a rule of syntax. JRuby's rules for naming variables fall into the latter category, in that a variable's name applies directly to its role or use within a JRuby program. Failure to correctly apply the naming rules outlined in Table 1 will result in errors.

Table 1. JRuby's rules: naming variables
Prefix Role indicated Example(s)
$ global variables $total, $count, $_
: symbol (that is, refers to the variable name itself) :foo, :size
@ class instance member @size, @foo
@@ class member variable (like a static member in Java) @@refCount, @@NORTH
upper-case letter constant (must be used for all class and module names) MyClass, MyModule
lower-case letter or underscore local variable or method name, depending upon context k, _id, name, getName

You'll have the opportunity to see exactly how these rules work in the examples that follow.


Back to top


Blocks and iterators

You might have noticed some unfamiliar (or less familiar) method names in the program output shown in Listing 2, such as times, downto, and step. These methods are known as iterators in JRuby. Iterators are methods that invoke a given block of code on a sequence of values. The sequence of values is determined by that iterator's implementation and by the type of object for which the iterator is defined. (Notice, here, that an iterator is a kind of member method of a class and not itself a class as in C++ or the Java language.)

As a simple example, consider the iterator each, which is implemented for every JRuby collection. The each iterator simply invokes the given block of code on each member of the collection. Thus, we could rewrite the example shown in Listing 1 to incorporate code specific to class Integer, as shown here:

3.methods.each { |m| print "#{m} " if not methods.index(m) }


This code is obviously more concise than the earlier example, where we used the for construct. Moreover, the approach is clearly less cumbersome than the equivalent Java code would be. The simplicity of the code lets us focus on the job at hand rather than the details of traversing a list and invoking operations upon individual members of that list.

No more for loop ...

Continuing with the methods of the Integer class, we see that the upto iterator passes successive integer values, beginning at the integer value itself and ending with the value specified by the function argument, into a block of code. Hence, we could write the following line to obtain a table with the squares of the numbers 1 through 5, inclusive:

1.upto(5) { |n| print "#{n}\t{n**2}\n" }


The step iterator works much like upto (or downto) except that it takes a step parameter which indicates the amount to add (or subtract) to the current value to obtain the next value. Employing such methods, it is easy to see how the need for a for construct disappears. (Indeed, JRuby's for statement is implemented via the each iterator of the Integer class.)

User-defined iterators

The iterators available from class to class vary depending on the purpose of and operations defined for that class. JRuby also lets us define our own iterators for our own classes (or rewrite iterators in JRuby's class library) using the yield statement. The yield statement transfers control from a function (or method) to the block passed to that function. For instance, the implementation of the upto iterator for the Integer object might be written as follows:

Class Integer
:
def upto (endNum)
for val in self.to_i..endNum
yield val
end
end
:
end


The special identifier self is used to refer to the current instance, functioning exactly like the this reference in the Java programming language. Also like the this reference, the self reference, when absent, is implicit.

The expression, self.to_i..endNum, forces the creation of an instance of class Range in JRuby. A Range object has a first value, a last value, and a method, succ, that defines how successive values after first are to be formed. The for construct takes advantage of the use of the Integer succ method to form a range from the value represented by self to that given as endNum. We use the inclusive Range object, denoted by two consecutive periods (..), rather than the exclusive Range object, represented by three consecutive periods (...).

No more loops!

There are actually two parameters in the definition of the upto method. The first is endNum and is evident from the method definition. However, the second parameter, the block, is in implicit formal parameter in the method. It is accessed automatically (if present) by invoking the yield statement. What all of this means is that the JRuby developer need never use a loop construct. Whether you take advantage of the extensive JRuby library or overwrite the appropriate methods in your own classes (for example, succ, each), you can use iterators to do most of the grunt work for you.


Back to top


JRuby's class act

We're ready to begin tackling class examples in JRuby. We'll write two classes, the first emphasizing JRuby's powerful text-processing features and the second demonstrating its potential when combined with the Java class library. You'll find the source for both class examples in the code download; click on the Code icon at the top or bottom of the article to access the code.

Our first class definition in JRuby is a rudimentary representation of an XML element of the following form:

'


Although the class is quite simple, it does a lot of work, as you can see in Listing 3.

Listing 3. Class excerpt from XmlElement.rb

# represent a well-formed XML element
# (that is, opening and closing tags are present) with proper nesting
class XmlElement

# class member
# matches strings of the form:
# '
@@xmlElement = /<([a-z]+)>((.|\s)*)<\/\1>/

# member attributes: make them readable/writable
attr_accessor :name, :children, :textContent

def initialize (text, isRoot=true)
# member variable:
# list of child elements
@children = []
# member variables:
# name of element derived from tag name
# text content of element (if any)
@name, @textContent = "DOC_ROOT", "" if isRoot

# add new elements while we get a match
text.scan(@@xmlElement) { | name, content |
newChild = XmlElement.new(content, false)
newChild.name = name
newChild.textContent = content if not content.include?('<')
@children.push(newChild)
}
end # initialize

def printTree (elem=self, indent="")
print indent, elem.name
print "[#{elem.textContent}]" if elem.textContent
print "\n"
indent += " "
elem.children.each { | elem | printTree(elem, indent) }
end # printTree
end # XmlElement


About the code

Quite a lot is happening in this code, so we'll go over the most important elements line by line. The class definition begins with the class keyword, followed by the class name. Names of classes in JRuby are constants, as signified by starting the name with an uppercase letter. The next line declares the regular expression that will serve as the template for the basic XML element. Note that this expression is an XmlElement class member, as signified by the prefix "@@". This class member is of type Regexp. We could use the new operator of the Regexp class to create it, but instead we use the more traditional syntax familiar to Perl developers.

Next, we introduce three symbols that will denote instance members in the class: name; children; and textContent. We prefix each with a colon (:), creating an object of type Symbol, which is required by the attr_accessor method of the Module class. Using this method is equivalent to making the members behave as if they had corresponding getters and setters, though we need use only the name of the attribute for reading or assigning to it. Within the body of a class method, we prefix the attribute with a "@", indicating that it is an instance member.

The initialize method is the first method to be called in any JRuby class upon its instantiation. Here, it is given the text of an XML element to parse. After initializing the @children list (the list that will hold the child elements), we begin to recursively define each of these elements. (Notice that we create a default root element to symbolize the top of the XML document. The default value of isRoot is set to true for a more convenient interface.)

We use the scan iterator in the String class to do most of the parsing work for us. The most basic form of the scan function takes a regular expression and returns an array of the strings within the string object invoking scan (that is, text) that match the expression. Another version of scan (our use of it) invokes a block of code on the matches. The interesting thing about scan is that it will process submatches in an expression. In our example, for instance, the @@xmlElement contains two subexpressions, ([a-z]+) and ((.|\s)*). These represent the name and the remainder of the content of an element, respectively. Each array element returned by the scan method, then, is itself a two-member array containing these two results. Thus, our block takes two arguments, name and content.

The block itself is straightforward. We create a new XmlElement, passing it the content found in the match. We set the name and the text content of the newly formed XmlElement and use the include? method of the String class to discover whether or not this block of content can serve as text content. (This, of course, is an admittedly unsophisticated test.) Finally, we push the newly created child element onto the list of children for the element.

XML document processing

The XmlElement.rb file in the source code download demonstrates JRuby's support for entering long (multi-line) strings. Here we'll look at just one approach. Typing the following directly into the interpreter will invoke the parser on the XML document:

load "XmlElement.rb" # access the XmlElement class
text = IO.readlines("test.xml").join
xmlDoc = XmlElement.new(text)
xmlDoc.printTree


The printTree method prints the elements discovered in the document along with their text content (if any). Child elements are indented for readability.


Back to top


Building a GUI

Our second class example will be considerably more extensive, because we're going to build a GUI calculator. This example will introduce two new JRuby classes, Hash and Proc, and demonstrate how Java classes can be accessed and used in a JRuby application. This example will also let you see how quickly and easily you can write complex applications in JRuby.

To run the calculator from the code source, type:

jruby Calculator.rb


Accessing Java classes

As in the previous example, we'll use the include_package method from the Module class to import Java packages into a JRuby program. This method is provided along with other classes and functions by the Java class library in JRuby. Thus, the typical JRuby application that utilizes Java classes starts something like this:

require 'java'
module
include_package ''
end


Note that we've used the require statement to include the Java library and define a module to represent a namespace in which the Java package will reside.

The Calculator interface

The calculator interface will consist of three components:

* A text field in which to enter an expression to be evaluated

* A 4 x 4 grid of buttons including the digits 0 through 9, the basic arithmetic operations, a decimal point, and an evaluation button (=)

* A function section containing a grid of buttons that perform common operations such as sin, cos, sqrt, etc.

Seems like a lot of work, doesn't it? Luckily for us, part of the fun of this example is seeing how JRuby can make our job incredibly simple and straightforward!

Start with the framework

We'll use the Java platform's Swing classes to build our GUI. The calculator itself can be implemented as a subclass of JFrame. Hence, we might start with something like the code in Listing 4:

Listing 4. Setting up the calculator

require 'java'
module Swing
include_package 'java.awt'
include_package 'javax.swing'
end
module AwtEvent
include_package 'java.awt.event'
end

$calculator = Swing::JFrame.new
class << $calculator

def init
end

end

$calculator.init
$calculator.setSize(400, 400)
$calculator.setVisible(true)


The require method loads JRuby's Java library into the interpreter and is required for any application that will take advantage of Java classes. We then define two modules, each representing a namespace for a set of Java packages. A module name, like a class name, must be a constant so it begins with an uppercase letter. We use the include_package method of the Module class to import the Java package into the module. To access classes in that package, we now refer to the module name followed by the namespace resolution operator (::), then followed by the desired Java class name.

The next bit of code may seem unusual to the Java programmer. We first define a global variable for the main calculator window by prefixing the identifier with a dollar sign ($). This class definition is known as an anonymous class in JRuby. Essentially, we want to create a class based on or inheriting from the object we've just created. (Due to limitations in the implementation of inheritance in JRuby, we cannot define a class that directly inherits from a Java class.) In defining our new subclass, we write an init method (since the initialize method has already been called in the creation of the $calculator object). We will need to call this method upon completing the class definition. (To some extent, this is akin to calling super() in a Java class constructor and then proceeding with the initialization of that class.)

Add the expression field

This code is straightforward. We simply want a label and a field in which the user can enter the expression to be evaluated. Listing 5 shows the new init method:

Listing 5. Initializing the expression field

def init
cp = getContentPane

# field for entering expression
exprPanel = Swing::JPanel.new(Swing::BorderLayout.new)
exprBox = Swing::Box.new(
Swing::BoxLayout::X_AXIS)
exprBox.add(Swing::Box::createHorizontalGlue)
exprBox.add(
Swing::JLabel.new("Enter an expression: "))
@exprField = Swing::JTextField.new(20)
exprBox.add(Swing::Box::createHorizontalStrut(4))
exprBox.add(@exprField)
exprBox.add(Swing::Box::createHorizontalGlue)
exprPanel.add(Swing::BorderLayout::NORTH, exprBox)
cp.add(Swing::BorderLayout::NORTH, exprPanel)
end


We make the text field an instance member because the listeners for the buttons will need access to its content. We can add these methods to permit the appropriate access:

def setExpression (expr)
@exprField.setText(expr)
end
def getExpression
@exprField.getText
end


Add the number pad

At this point we're really starting to see what makes JRuby great. The next thing we need is a 4 x 4 grid of buttons, which we'll use to create the traditional number pad. As you'll recall, the typical calculator pad includes the numbers 0 through 9, the four basic arithmetic operators (add, subtract, divide, multiply), and the evaluation, or equals, button. To keep things simple, all of the buttons (except the evaluation button) will, when pressed, put the symbol they represent into the right-most space in the expression field. The evaluation button will perform the actual evaluation.

In Listing 6, we see the relevant code from the init method.

Listing 6. Initializing the number pad

# form and add the number pad
buttons = [
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+'
]
numPadPanel = Swing::JPanel.new(
Swing::GridLayout.new(4, 4))
buttons.each { |symbol|
numPadButton = Swing::JButton.new(symbol)
numPadButton.setActionCommand(symbol)
numPadButton.addActionListener()
numPadPanel.add(numPadButton)
}
cp.add(numPadPanel, Swing::BorderLayout::CENTER)


We iterate through the symbols for which we wish to create a button. For each symbol that is to be represented on the calculator number pad, we first create a new JButton with text consisting of the symbol being processed and add a button listener (although this has yet to be written). Finally, we add the newly formed button to the numPadPanel. Upon completing the iteration, we attach the numPadPanel to the main window. Think about performing the same task in the Java programming language and you'll see why so many developers appreciate JRuby!

The button listener for the number pad buttons must update the expression field with the symbol on the button so long as the symbol is not the equals sign. If the evaluation button is pressed, we want to evaluate the expression. We define such a listener as a global variable, as shown in Listing 7:

Listing 7. Defining the listener

$numListener = AwtEvent::ActionListener.new
def $numListener.actionPerformed (event)
comm = event.getActionCommand
$calculator.setExpression(
$calculator.getExpression + comm) if
comm != "="
$calculator.setExpression(
eval($calculator.getExpression).to_s) if
comm == "="
end
end


Here, we're employing the same strategy as we did when we made the $calculator object an instance of JFrame; only the syntax is different. Indeed, Java developers will find that this syntax mirrors that used in defining an anonymous inner class in the Java language.

Add the function panel

Our final task is to implement the panel that houses the function buttons. We use a JRuby Hash (which behaves just like a Java java.util.HashMap), keyed by the function name as it appears on the button. The values of the Hash object are known as Proc objects (which are similar to closures) and are created with the Kernel class's proc method. The final portion of the init method is as follows:

Listing 8. Initializing the function panel

# form and add the function panel
@fnMap = {
'sin' => proc { |n| Lang::Math.sin(n) },
'cos' => proc { |n| Lang::Math.cos(n) },
'ln' => proc { |n| Lang::Math.log(n) },
'sqrt' => proc { |n| Lang::Math.sqrt(n) }
}
fnPanel = Swing::JPanel.new(
Swing::GridLayout.new(1, 4))
@fnMap.each_key { | fnName |
fnButton = Swing::JButton.new(fnName)
fnButton.setActionCommand(fnName)
# we'll write the $fnListener momentarily --
# it's quite similar to the $numPadListener just discussed
fnButton.addActionListener($fnListener)
fnPanel.add(fnButton)
}
cp.add(fnPanel, Swing::BorderLayout::SOUTH)


Note that each Proc object formed encapsulates a block of code that simply consists of invoking some mathematical function and the argument given to the block. The argument is passed when we invoke the call method on the Proc object.

We make the fnMap an instance member so that, once again, we can provide an accessor to it in the listener we will need for the function buttons. We can add the following method to the class to provide the appropriate access:

def getFnForName (name)
@fnMap[name]
end


The listener is defined globally and is created using the same method we used to create the button listener for the number pad buttons:

$fnListener = AwtEvent::ActionListener.new
def $fnListener.actionPerformed (event)
val = $calculator.getExpression.to_f
fn = $calculator.getFnForName(event.getActionCommand)
$calculator.setExpression(fn.call(val).to_s)
end


After we retrieve the value from the expression field (we assume that it has been evaluated to a single value), we can get the Proc object we need and invoke the call method, passing it the value we have retrieved from the expression field. We then convert it back to a string with the to_s method and reset the expression field.

And fini!

Figure 1 shows the GUI produced by this application. (It's not pretty, but it works!)

Figure 1. Sample of calculator GUI
Sample of Calculator GUI showing the digit and function grid of buttons

In addition to being fully functional, the calculator example demonstrated here (and found in Resources) can easily be extended. To expand the calculator's functions, you need simply add an appropriate entry for each new function to the $fnMap.


Back to top


Conclusion

JRuby is a powerful and flexible language that offers a rich library and extensive features. Its support of iterators, its convenient text-processing functions, and, of course, its access to the vast set of class Java libraries and APIs provide an excellent environment in which to quickly and easily write robust applications, large or small.

In this installment of the alt.lang.jre series, we have introduced JRuby, using simple, familiar examples to demonstrate its utility as a rapid-development language. You'll find the source code for the article in the Resources section. As previously mentioned, some of the class examples can be easily expanded as a further exercise.

See Resources to learn more about JRuby and other alternate languages for the Java platform -- and be sure to tune in again next month!

No comments: