JETZT ONLINE BESTELLEN
Add to Cart
JRuby Cookbook

First Edition November 2008
ISBN 978-0-596-51980-3
222 Seiten
EUR29.00

Weitere Informationen zu diesem Buch

Inhaltsverzeichnis | Kolophon |


Inhaltsverzeichnis

	
Chapter 1: Getting Started
Inhaltsvorschau
JRuby is an open source implementation of the Ruby programming language for the Java Virtual Machine (JVM). It allows Ruby applications to be run within a Java Virtual Machine and interface with libraries written in either Java or Ruby. Although the JRuby project was initiated in 2001, interest in JRuby has grown significantly over the last few years, reflecting an overall growth in interest in Ruby sparked by the success of the Ruby on Rails framework. Sun has contributed to JRuby’s success by employing members of the core development team and providing support for JRuby in the NetBeans development environment, among other efforts. The website for the JRuby project is currently http://www.jruby.org.
Ruby is a dynamic object-oriented programming language created by Yukihiro Matsumoto, known by the nickname Matz, in the mid-1990s. Ruby follows a style of versioning similar to the Linux kernel, where an even minor version number indicates a stable release and an odd minor version number indicates a development release. As a result, there are two current versions of Ruby: 1.8.6, released in March 2007, is the current stable release, and 1.9.0, released in December 2007, is the current development release. The standard Ruby interpreter is written in C. There are several alternate of the interpreter, including JRuby, IronRuby (for Microsoft’s .NET framework), and Rubinius. Ruby does not have a formal language specification; however, one is being developed through the wiki at http://spec.ruby-doc.org.
As an object-orientated language, many of the underlying concepts of Ruby will be familiar to Java developers, even if the syntax is not. The biggest exception to this is Ruby’s support for blocks. In Ruby, a block is a grouping of code that gets passed to a method call. The receiving method can invoke the block any number of times and can pass parameters to the block. Support for a similar type of element, a closure, is being contemplated for inclusion in Java 7; there are several competing proposals and it is unclear which proposal, if any, will be adopted. contains a simple Ruby class demonstrating the two ways of defining a block in Ruby. The former syntax, using braces, is typically used to create a block for a single statement. The latter syntax, using the
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
JRuby is an open source implementation of the Ruby programming language for the Java Virtual Machine (JVM). It allows Ruby applications to be run within a Java Virtual Machine and interface with libraries written in either Java or Ruby. Although the JRuby project was initiated in 2001, interest in JRuby has grown significantly over the last few years, reflecting an overall growth in interest in Ruby sparked by the success of the Ruby on Rails framework. Sun has contributed to JRuby’s success by employing members of the core development team and providing support for JRuby in the NetBeans development environment, among other efforts. The website for the JRuby project is currently http://www.jruby.org.
Ruby is a dynamic object-oriented programming language created by Yukihiro Matsumoto, known by the nickname Matz, in the mid-1990s. Ruby follows a style of versioning similar to the Linux kernel, where an even minor version number indicates a stable release and an odd minor version number indicates a development release. As a result, there are two current versions of Ruby: 1.8.6, released in March 2007, is the current stable release, and 1.9.0, released in December 2007, is the current development release. The standard Ruby interpreter is written in C. There are several alternate of the interpreter, including JRuby, IronRuby (for Microsoft’s .NET framework), and Rubinius. Ruby does not have a formal language specification; however, one is being developed through the wiki at http://spec.ruby-doc.org.
As an object-orientated language, many of the underlying concepts of Ruby will be familiar to Java developers, even if the syntax is not. The biggest exception to this is Ruby’s support for blocks. In Ruby, a block is a grouping of code that gets passed to a method call. The receiving method can invoke the block any number of times and can pass parameters to the block. Support for a similar type of element, a closure, is being contemplated for inclusion in Java 7; there are several competing proposals and it is unclear which proposal, if any, will be adopted. contains a simple Ruby class demonstrating the two ways of defining a block in Ruby. The former syntax, using braces, is typically used to create a block for a single statement. The latter syntax, using the
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Installing JRuby
Inhaltsvorschau
You want to install JRuby.
Download and extract the latest binary release from the JRuby website, http://www.jruby.org. Add the bin directory to the PATH environment variable.

Windows

The JRuby website makes binary releases available in both ZIP and TGZ file formats. Since Windows XP, Windows operating system software has included support for ZIP files. Commercial and open source software packages are available that include support for TGZ files, such as WinZip (http://www.winzip.com), 7-Zip (http://www.7-zip.org), and IZArc (http://www.izarc.com).
It is not necessary to install JRuby in any particular location on your computer. My preference is to install Java libraries and executables in subdirectories of C:\java. The results of extracting the binary for the latest release at the time of this writing, 1.1, can be seen in .
Figure : Extracted JRuby binary build
After extraction, JRuby is ready to be used. The simplest way to see JRuby in action is by running jirb, JRuby’s version of Interactive Ruby (irb). Like irb, jirb allows you to execute Ruby statements and immediately see the results of each statement. JRuby includes both command-line and GUI versions of jirb in the bin directory. The version, seen in , can be run by executing bin\jirb.bat; the GUI version, seen in , can be run by executing bin\jirb_swing.bat. In both figures, some trivial Ruby code has been executed. You can see that both the output of the puts method (Hello World) and its result (nil) have been output.
Figure : Command-line jirb
Figure : jirb GUI
If you launch either jirb.bat or jirb_swing.bat from Windows Explorer and all you see is a black window appear and then disappear quickly, the likely cause is that you do not have the JAVA_HOME environment variable set, or the value of this environment variable is incorrect. To set environment variables in Windows, use the System control panel’s Advanced tab.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Managing Packages with RubyGems
Inhaltsvorschau
You want to install Ruby on Rails or other Ruby packages for use with JRuby.
Use the RubyGems support built into JRuby. Once JRuby has been installed, you can immediately start using RubyGems to manage Ruby packages by running the gem script included in JRuby’s bin directory. To install a package, run:
$ gem install packagename
For example, to install the Ruby on Rails web framework, use:
$ gem install rails
RubyGems is the standard package management and distribution system for Ruby packages. There are thousands of packages, referred to as gems, available through the default RubyGems repository at http://gems.rubyforge.org. Although some gems are specific to the C Ruby implementation or JRuby, most are compatible with any Ruby implementation.
Common RubyGems commands include install, query, update, uninstall, and rdoc. The full list can be output by using the help command:
$ gem help commands

GEM commands are:



    build             Build a gem from a gemspec

    cert              Manage RubyGems certificates and signing settings

    check             Check installed gems

    cleanup           Clean up old versions of installed gems in the local

                      repository

    contents          Display the contents of the installed gems

    dependency        Show the dependencies of an installed gem

    environment       Display information about the RubyGems environment

    fetch             Download a gem and place it in the current directory

    generate_index    Generates the index files for a gem server directory

    help              Provide help on the 'gem' command

    install           Install a gem into the local repository

    list              Display all gems whose name starts with STRING

    lock              Generate a lockdown list of gems

    mirror            Mirror a gem repository

    outdated          Display all gems that need updates

    pristine          Restores installed gems to pristine condition from files

                      located in the gem cache

    query             Query gem information in local or remote repositories

    rdoc              Generates RDoc for pre-installed gems

    search            Display all gems whose name contains STRING

    server            Documentation and gem repository HTTP server

    sources           Manage the sources and cache file RubyGems uses to search

                      for gems

    specification     Display gem specification (in yaml)

    uninstall         Uninstall gems from the local repository

    unpack            Unpack an installed gem to the current directory

    update            Update the named gems (or all installed gems) in the local

                      repository

    which             Find the location of a library



For help on a particular command, use 'gem help COMMAND'.



Commands may be abbreviated, so long as they are unambiguous.

e.g., 'gem i rake' is short for 'gem install rake'.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using Both Ruby and JRuby
Inhaltsvorschau
You have Ruby and JRuby installed on the same computer and want to ensure that a Ruby script is processed by the correct interpreter.
Use the -S command-line argument for the ruby and jruby executables. For example, RubyGems is traditionally invoked with a command like:
gem install rails
Instead, use:
$ jruby –S gem install rails
or:
$ ruby –S gem install rails
Popular Ruby packages such as Rake, Ruby on Rails, and RubyGems include their own executable Ruby scripts that most guides, both online and print, instruct you to invoke directly. Whether these scripts run with Ruby or JRuby depends on how you’ve configured the PATH environment variable, which platform you use, and what package is involved. Because there are so many variables, this recipe prescribes using a single, consistent method, passing the script name through the -S command-line argument to either the ruby or jruby executables.
The -S command-line option instructs Ruby and JRuby to load a script file from the PATH. JRuby includes its own copies of the Rake and RubyGems scripts in bin/rake and bin/gem, respectively, but they are verbatim copies of the original scripts. As a result, it doesn’t matter which version of the script you execute, only the interpreter with which you execute it.
This advice is particularly significant in the context of the RubyGems script, gem. To create a new Rails application, you could run either:
$ ruby –S rails sampleapp
or:
$ jruby –S rails sampleapp
and see the same result. However, running:
$ ruby –S gem install rails
and:
$ jruby –S gem install rails
will install the Rails gem in two different locations. You can see this by passing environment to the gem script:
$ ruby -S gem environment

RubyGems Environment:

  - RUBYGEMS VERSION: 1.0.1 (1.0.1)

  - RUBY VERSION: 1.8.5 (2007-09-24 patchlevel 114) [i386-linux]

  - INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8

  - RUBY EXECUTABLE: /usr/bin/ruby

  - RUBYGEMS PLATFORMS:

    - ruby

    - x86-linux

  - GEM PATHS:

     - /usr/lib/ruby/gems/1.8

  - GEM CONFIGURATION:

     - :update_sources => true

     - :verbose => true

     - :benchmark => false

     - :backtrace => false

     - :bulk_threshold => 1000

  - REMOTE SOURCES:

     - http://gems.rubyforge.org

$ 
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Sharing RubyGems
Inhaltsvorschau
You already have a number of RubyGems installed and want to use those gems from JRuby without reinstalling the gems.
Set the GEM_HOME environment variable to your existing RubyGems installation location. This value can be seen in the output of gem environment, where it is referred to as the installation directory:
$ ruby -S gem environment | grep -i 'installation directory'

- INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8

$ export GEM_HOME=/usr/lib/ruby/gems/1.8

$ jruby -S gem environment | grep -i 'installation directory'

- INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8
Whereas some RubyGems are implemented entirely in Ruby, many are implemented in a combination of Ruby and C (or, in a growing number of cases, Ruby and Java). Pure-Ruby gems can be installed using either JRuby or C Ruby. However, those in a mixture can only be installed using a compatible interpreter. The list of supported platforms for each interpreter can be seen in the output of gem e⁠n⁠v⁠i⁠r⁠o⁠n⁠ment. Because the RubyGems runtime knows this list of supported platforms, it is possible to mix gems supporting different platforms in the same directory; the runtime will select the appropriate libraries.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Referencing Java Classes from Ruby
Inhaltsvorschau
You want to write Ruby code that uses one or more Java classes.
First, you need to tell JRuby that you will be referencing Java classes from your Ruby code. Do this by including an include declaration at the top of your Ruby file:
include Java
The syntax for referencing a specific Java class depends on the package in which the class resides. For packages starting with java, javax, org, and com, you can simply the fully qualified class name or use an import statement, as shown in .
Example . Creating a Java TreeMap from Ruby
# using the fully-qualified class name

map = java.util.TreeMap.new



# using an import statement

import java.util.TreeMap

map = TreeMap.new
For classes that reside in a package that does not begin with java, javax, org, or com, as well as classes in the default package, you need to use the include_class function, as in .
Example . Referencing a Java class with include_class
include_class 'EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap'



map = ConcurrentHashMap.new
The include_class function can also handle classes in packages starting with java, javax, org, and com if you don’t want to switch back and forth.
The include_class function can also be used to create aliases in cases where a Java class name conflicts with a Ruby class name. To do this, pass a block to the function. aliases the Java String class as JString so that it does not conflict with Ruby’s String class.
Example . Creating an alias to avoid class name conflicts
include Java



include_class 'java.lang.String' do |package,name|

    "JString"

end



p JString.new("A quick brown fox").indexOf("brown")
You can pass multiple class names to the include_class as a list. In this case, you could provide the appropriate alias using a case statement, as seen in .
Example . Aliasing multiple classes with case
include_class ['java.lang.String','java.lang.Integer'] do |package,name|

    case name

    when "String"

        "JString"

    when "Integer"

        "JInteger"

    end

end
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Converting a Ruby Array into a Java Array
Inhaltsvorschau
You need to pass a Ruby array to a method that accepts a Java array of a specific type.
Call the Ruby array’s to_java method with an argument specifying the component type of the array. For example, creating an array of javax.xml.transform.stream.StreamSource objects would be done like this:
import javax.xml.transform.stream.StreamSource



cnn = StreamSource.new "http://rss.cnn.com/rss/cnn_topstories.rss"

mtv = StreamSource.new "http://www.mtv.com/rss/news/news_full.jhtml"
# Call a transforming Java API. This method would have been declared

# with this signature:

# public String transform(StreamSource[] sources)

p transformer.transform([cnn,mtv].to_java(StreamSource))
Primitives, as well as java.lang.String, have Ruby symbols assigned to them. For , to create an array of int primitives:
[1,2,3,4,5,6,7,8,9,10].to_java(:int)
This JRuby feature is critical for accessing Java APIs. For example, calling a method through Java Management Extensions (JMX) involves passing two arrays to the invoke() method of javax.management.MBeanServer, one of Object instances, storing the method parameters, and one of String instances, storing the method signature. To call invoke() from JRuby, you would do something like this:
brokerName = ObjectName.new('org.apache.activemq:BrokerName=localhost,Type=Broker')

params = ["MyQueue"].to_java()

signature = ["java.lang.String"].to_java(:string)

server.invoke(brokerName, 'addQueue', params, signature)
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Adding JAR Files to the Classpath
Inhaltsvorschau
You want to reference a Java class which is contained in a JAR file that isn’t already included in your classpath.
Call Ruby’s require method with the path to the JAR file. This path can be relative to the current working directory:
require 'lib/commons-logging-1.1.jar'
or an absolute path:
require '/opt/java/commons-logging/bin/commons-logging-1.1.jar'
If you are using Windows, this path can have either type of slash:
require 'c:\java\commons-logging-1.1\bin\commons-logging-1.1.jar'

# or

require 'c:/java/commons-logging-1.1/bin/commons-logging-1.1.jar'
Although this is an extremely useful feature of JRuby, it should be used with caution, especially if you use absolute paths that are platform- and installation-specific. Relative paths can seem like a better solution, but are actually more limiting, as they are evaluated from the current working directory, not the script’s directory. Yet all is not lost.
An interesting aspect of this feature of JRuby is that the JAR file is added to the classpath dynamically, while the application is running. This allows you to use Ruby’s string interpolation functionality to create absolute paths. includes a method that creates a path to a JAR file in a local Maven repository.
Example . Creating a JAR file path dynamically
# Set the HOME environment variable if USERPROFILE is set

ENV['HOME'] = ENV['USERPROFILE'] if (ENV['USERPROFILE'])



def require_from_maven(group,artifact,version)

    maven_path = "#{group}/#{artifact}/#{version}/#{artifact}-#{version}.jar"

    require "#{ENV['HOME']}/.m2/repository/#{maven_path}"

end
Application code could use require to include this script and then use the require_from_maven method to reference a specific JAR file:
require 'require_from_maven'

require_from_maven "commons-logging", "commons-logging", "1.1"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Extending a Java Class in Ruby
Inhaltsvorschau
To use a Java API, you need to create a Ruby class that subclasses a Java class.
Use the standard Ruby superclassing operator < and specify the Java class you want to subclass. shows a Ruby class that extends the Java Thread class and overrides the run() method.
Example . Subclassing a Java class in Ruby
include Java



class MyThread < java.lang.Thread

    def run

        puts 'hello world'

    end

end



MyThread.new.start
The fact that the same syntax is used to extend both Java and Ruby classes is an important design feature of JRuby, as it furthers the seamless integration between the two languages.
One notable exception to this recipe is classes that use Java 5 generics. Currently, these cannot be subclassed with Ruby classes.
Abstract Java classes can also be extended by Ruby classes. Examples and show an example of an abstract Java class and a concrete Ruby class that extends the former. The hello() method, declared abstract in the Java class, is implemented in the Ruby class.
Example . An abstract Java class
package org.jrubycookbook.ch01;



public abstract class AbstractElement {

    public abstract void hello();



    public void sayHello(int count) {

        for (int i = 0; i < count; i++) {

            hello();

        }

    }

}
Example . Ruby class that subclasses an abstract Java class
include Java



import org.jrubycookbook.ch01.AbstractElement



class RubyElement < AbstractElement

    def hello

        puts 'hello world'

    end

end



RubyElement.new.sayHello 5
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Implementing a Java Interface in Ruby
Inhaltsvorschau
To use a Java API, you need to create a Ruby class that implements a Java interface.
Create your class with method names that match the names in the Java interface. As of version 1.1, JRuby runtime supports the use of duck typing for implementing Java . Duck typing, seen in many dynamic languages, including Ruby, means that the type of an object is determined based on the methods implemented by the object. shows this technique in action as a new Java thread by passing the an object that implements the java.lang.Runnable interface. The HelloT⁠h⁠read class contains a zero-argument run method that corresponds to the method defined in java.lang.Runnable. JRuby requires no additional type information in the HelloT⁠h⁠read class to instantiate the Thread object.
Example . Ruby implementation of a Java interface
include Java



class HelloThread

    def run

        puts 'hello world'

    end

end



java.lang.Thread.new(HelloThread.new).start
There are few situations when duck typing isn’t sufficient and you’ll need to provide additional type information to the interpreter. One case is when a duck-typed JRuby object is passed as an argument to an overloaded Java method. Without additional Java type information, the JRuby interpreter doesn’t definitively know which method to execute. The solution is to use Ruby’s include statement to assign an explicit Java interface to a Ruby class. This provides the JRuby interpreter with enough information about the object to execute the correct method. In , the HelloThread class is assigned the Runnable interface. As a result, JRuby calls the desired exec() method and runnable is output to the console.
Example . Declaring Java interfaces in JRuby
Balloon.java



public interface Balloon {

    void pop();

}



Bubble.java



public interface Bubble {

    void pop();

}



Child.java



public class Child{

    public void give(Bubble bubble){

        System.out.println("Thanks for the bubble.");

        bubble.pop();

    }

    public void give(Balloon balloon){

        System.out.println("Thanks for the balloon.");

        balloon.pop();

    }

}
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Opening Java Classes with JRuby
Inhaltsvorschau
You want to add methods to a Java class.
Import the Java class so that the class can be referenced, and add methods as you would to any Ruby class.
In Ruby, class definitions are never finalized; new methods can be added at any time. This is perhaps one of the most significant differences between Java and Ruby. In Java, class definitions are tightly bound to filenames and directory structures. The complete definition of the Java class java.util.HashMap will be found in a file named /java/util/HashMap.class. In Ruby, no such relationship exists and classes can be defined across multiple source files. With JRuby, it’s possible to apply this language feature to Java classes. shows a simple example of enhancing the java.util.HashMap class with a method named is?.
Example . Adding a method to HashMap
include Java



import java.util.HashMap



class HashMap

    def is?(key,value)

        value == get(key)

    end

end
As you can see in this example, within the new method we can call methods defined by the original Java class. Once this code is executed, JRuby instances of the HashMap class, including those already created, will have this new method. This even applies to instances of the class created by Java code. Examples and contain a Java class that creates a HashMap object and Ruby code that opens the HashMap class and exercises the new method.
Example . A simple class to generate a HashMap object
package org.jrubycookbook.ch01;
import java.util.*;



public class MapMaker {

    public static Map makeMap() {

        Map m = new HashMap();

        m.put("k1", "v1");

        m.put("k2", "v2");

        return m;

    }

}
Example . Applying open class semantics to an instance created with Java code
include Java



import java.util.HashMap

import org.jrubycookbook.ch01.MapMaker



h = MapMaker.makeMap()



class HashMap

    def isNot?(key,value)

        value != get(key)

    end

end



puts (h.isNot? 'k1', 'v1')

puts (h.isNot? 'k2', 'v3')
However, any added methods are only visible to the JRuby runtime. If you were to pass an instance of this modified
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Setting Up Eclipse for JRuby Development
Inhaltsvorschau
You use the Eclipse Integrated Development Environment (IDE) for Ruby development and want to run Ruby code easily with the JRuby interpreter.
When using the Ruby Development Tools (RDT) plugin, create a new Ruby VM definition that is pointed at your JRuby installation location and whose type is set to JRuby VM. When using the Dynamic Language Toolkit (DLTK) plugin, create a new Ruby interpreter definition that references the JRuby launch script: bin\jruby.bat (for Windows) or bin/jruby (for Linux and Mac OS X) from your JRuby installation.
Both RDT and DLTK can be configured to work with multiple Ruby interpreters. RDT has a specific setting available for the JRuby interpreter, whereas DLTK simply treats JRuby as a generic Ruby interpreter.

RDT

RDT, available from http://rubyeclipse.sourceforge.net, supports configuration of Ruby interpreters based on the installation directory. To add JRuby as an interpreter, open the Preferences dialog and locate the Installed Interpreters page. Click the Add button to open the Add RubyVM dialog (seen in ). In this dialog, select JRuby VM as the RubyVM type and select the JRuby installation directory as the RubyVM home directory. You can also override the display name with something more user-friendly. Once you’re satisfied with the settings, click OK.
Figure : RDT Add RubyVM dialog

DLTK

The Dynamic Language Toolkit project, hosted at http://www.eclipse.org/dltk, is a broad project sponsored by the Eclipse Foundation to provide general support for languages in the Eclipse development environment. Currently, support is available through the DLKT project for Ruby, TCL, and Python. The DLTK Ruby plugin does not make a distinction between a standard Ruby interpreter and the JRuby interpreter. Just as when configuring RDT, open the Preferences dialog and locate the page. Click the Add button to open the “Add interpreter” dialog, seen in . Select the
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Setting Up NetBeans for JRuby Development
Inhaltsvorschau
You want to develop Ruby applications with NetBeans.
Download NetBeans 6.5 from http://www.netbeans.org and run the installer. NetBeans is available in a variety of bundles; both the Ruby and All bundles include support for Ruby development. In addition to Ruby, the All bundle includes support for Java, Web, Mobile, and C/C++, as well as both Apache Tomcat and Sun GlassFish application servers.
If you are already using NetBeans 6.5, Ruby support can be installed using the Plugins dialog, seen in . This plugin adds new NetBeans project types for Ruby and Rails, graphical debuggers for Ruby and Rails, a Ruby Code Editor, and a RubyGems client.
Figure : Installing the NetBeans Ruby plugin with the Plugins dialog
Once the Ruby plugin has been installed, use the Ruby page in the Ruby Platforms dialog seen in to manage the Ruby runtimes used by your projects. Notice the options to add new runtimes or modify an interpreter’s gem repository location and debug level. By default, your Ruby project will use the JRuby runtime shipped with the Plugin, but you can assign a specific Ruby Platform to your application by using the project’s properties dialog.
After several years of playing second fiddle to Eclipse, Sun has recently made some significant investments in the NetBeans project, and it shows—nowhere more so than in the Ruby plugin. The NetBeans Ruby Code Editor includes syntax highlighting, code coloring, refactoring support, and powerful code completion capabilities. The code completion functionality can be seen in . The editor displays a list of possible methods in a small window, including built-in and user-defined Ruby classes. Hitting the space bar at this point inserts the complete name into the editor.
Figure : NetBeans Ruby Platform Manager dialog
Figure : NetBeans Ruby code completion
You can also change the editor’s font and highlighting colors or change the key bindings to match your personal preferences. Configuration is done in the Options dialog seen in . Choose the Fonts & Colors tab and select a Profile from the list. OS X Ruby developers might be interested in a TextMate theme, Aloha (
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Platform Detection in a JRuby Application
Inhaltsvorschau
You would like to detect the platform used by the Ruby runtime and customize your code for a JRuby runtime environment.
You can detect whether your application is running in JRuby by evaluating the JRUBY_V⁠E⁠R⁠SION system variable. This value will always be defined in a JRuby application but never in any other Ruby runtime. The generate_random_number method in uses the random number generator from the Java Math class in a JRuby ; , the application calls Ruby’s rand method.
Example . JRuby platform detection
class DetectionExample



  def generate_random_number

    if(defined?(JRUBY_VERSION))

     require 'java'

     puts 'executing java method'

     java.lang.Math.random

    else

     puts 'executing ruby method'

     rand(0)

    end

  end



end



d = DetectionExample.new

puts d.generate_random_number
The RUBY_PLATFORM variable has information about the runtime environment and is set to java in JRuby. It was used with early versions of JRuby for platform detection, but the JRUBY_VERSION variable was later added to identify unequivocally that the code was running in JRuby and not another Ruby interpreter written in Java. The new variable also opened up the possibility for JRuby version-specific code.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 2: JRuby on Rails
Inhaltsvorschau
Since its introduction in mid-2004, the Ruby on Rails web framework has rapidly gained a significant following within the web development community. It is the single largest factor in the overall increase in interest in the Ruby programming language. Likewise, JRuby’s ability to run Rails applications inside a Java Virtual Machine has been a driver for interest in JRuby. This chapter explores some techniques for running Rails applications in a Java environment.
Ruby on Rails is a framework for developing web applications that follows the model-view-controller (MVC) architecture. The notion of Convention over Configuration is stressed throughout the framework, most prevalently within ActiveRecord, the object-relational-mapping (ORM) subsystem. ActiveRecord uses database metadata (table and column names) to dynamically define domain classes. Using ActiveRecord, simply adding a new column to a database table automatically adds a corresponding field to the related domain class.
Running Rails applications on JRuby provides several advantages:
  • Rails applications can be deployed into existing Java EE containers such as Tomcat, JBoss, and GlassFish.
  • Through Java Database Connectivity (JDBC), Rails applications can be connected to virtually any database for which a JDBC driver exists.
  • Rails applications can access container-managed database connection pools through Java Naming and Directory Interface (JNDI).
In short, the combination of JRuby and Rails produces an enterprise-friendly package that blends seamlessly into an existing Java EE environment. From an application ’s perspective, the Rails application is just another Java EE web application; if JNDI data sources are used, the application deployer never even needs to look at Rails configuration files.
Beyond JRuby, the primary library that provides the bridge between the Java EE container and Rails is called JRuby-Rack. JRuby-Rack is basically a Java servlet filter that dispatches requests to a Rails application running inside JRuby. JRuby-Rack creates a pool of JRuby runtime instances. Configuration of the JRuby-Rack servlet is discussed in . Early approaches to Java EE packaging and servlet integration used the GoldSpike project, but that code has been deprecated and replaced by JRuby-Rack.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
Since its introduction in mid-2004, the Ruby on Rails web framework has rapidly gained a significant following within the web development community. It is the single largest factor in the overall increase in interest in the Ruby programming language. Likewise, JRuby’s ability to run Rails applications inside a Java Virtual Machine has been a driver for interest in JRuby. This chapter explores some techniques for running Rails applications in a Java environment.
Ruby on Rails is a framework for developing web applications that follows the model-view-controller (MVC) architecture. The notion of Convention over Configuration is stressed throughout the framework, most prevalently within ActiveRecord, the object-relational-mapping (ORM) subsystem. ActiveRecord uses database metadata (table and column names) to dynamically define domain classes. Using ActiveRecord, simply adding a new column to a database table automatically adds a corresponding field to the related domain class.
Running Rails applications on JRuby provides several advantages:
  • Rails applications can be deployed into existing Java EE containers such as Tomcat, JBoss, and GlassFish.
  • Through Java Database Connectivity (JDBC), Rails applications can be connected to virtually any database for which a JDBC driver exists.
  • Rails applications can access container-managed database connection pools through Java Naming and Directory Interface (JNDI).
In short, the combination of JRuby and Rails produces an enterprise-friendly package that blends seamlessly into an existing Java EE environment. From an application ’s perspective, the Rails application is just another Java EE web application; if JNDI data sources are used, the application deployer never even needs to look at Rails configuration files.
Beyond JRuby, the primary library that provides the bridge between the Java EE container and Rails is called JRuby-Rack. JRuby-Rack is basically a Java servlet filter that dispatches requests to a Rails application running inside JRuby. JRuby-Rack creates a pool of JRuby runtime instances. Configuration of the JRuby-Rack servlet is discussed in . Early approaches to Java EE packaging and servlet integration used the GoldSpike project, but that code has been deprecated and replaced by JRuby-Rack.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Installing and Setting Up Rails
Inhaltsvorschau
You want to run Ruby on Rails with JRuby.
Install the latest Ruby on Rails gem with this command:
$ jruby –S gem install rails
If you’re running Rails 2.x, it is recommended you install the jruby-openssl gem to take advantage of all the security features and session storage options. This gem is the Java implementation of the openssl gem:
$ jruby –S gem install jruby-openssl
Now create your Rails application with JRuby:
$ jruby –S rails MyKillerApplication
Test your new Rails application:
$ cd MyKillerApplication

$ jruby ./script/server
Open your browser and go to http://localhost:3000. You should see the ubiquitous Rails welcome screen, shown in .
Figure : Ruby on Rails welcome screen
The next step is to configure Rails to connect to your database. The JRuby team has made this easy by allowing Rails to use the familiar and widely supported Java JDBC drivers. You first need to install the activerecord-jdbc-adapter gem:
$ jruby –S gem install activerecord-jdbc-adapter –y –-no-ri –-no-rdoc
The gem allows the Rails database management system, ActiveRecord, to use a JDBC connection or connection pool for database access. This can be conveniently configured in the standard Rails database.yml file by specifying the JDBC URL or a JNDI address. The example database.yml in is configured to use a JDBC connection in the development environment and container-provided javax.sql.DataSource with the JNDI name java:comp/env/jdbc/rails_db in the production environment. Remember to include the JDBC driver in your classpath when using the standard jdbc adapter.
Example . Example database.yml using JDBC
development:

  adapter: jdbc

  url: jdbc:mysql://localhost:3306/jrubycookbook_development

  driver: com.mysql.jdbc.Driver

  username: jruby

  password: cookbook



production:

  adapter: jdbc

  jndi: java:comp/env/jdbc/rails_db

  driver: com.mysql.jdbc.Driver
The JRuby Extras project contains a set of database adapters for the most commonly used open source databases by Java developers, including h2, JavaDB (Derby), MySQL, HSQLDB (Hypersonic), and Postgres. The adapter gems give you the option of using ordinary Rails database configuration values in your
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Packaging Rails As a Java EE Web Application
Inhaltsvorschau
You want to package a Rails app as a Java EE web application for deployment onto a standard Java EE web container.
Use Warbler to package your Rails application as a WAR file. Start by installing the gem:
$ jruby –S gem install warbler
This gem adds the warble command, which allows you to create, configure, and clean up the WAR file. All Warbler commands should be executed in the root directory of your Rails application. Start by creating a Warbler configuration file with this :
$ jruby –S warble config
The new configuration file is written to config/warble.rb. This file allows you to set most of the necessary options for building your WAR and determining how Rails will run in the web container. Open warble.rb and configure config.webxml.rails.env to the of your Rails deployment. Next, add all the gems used by your web application to the config.gems hash except for the rails gem. Rails is included in the default hash. An example warble.rb file showing these options can be seen in .
Example . Example Warbler configuration file
# Value of RAILS_ENV for the webapp

config.webxml.rails.env = 'development'



# List of all your application's gems

config.gems << "activerecord-jdbcmysql-adapter"

config.gems << "jruby-openssl"
You’re ready to create a WAR file by running this command:
$ jruby –S warble war
This generates a WAR file named the Rails project home directory name by default. For example, if our Rails project was in the MyKillerApplication folder, the WAR file would be named MyKillerApplication.war. This WAR file can then be deployed into your Java EE container using the container’s deployment process.
Warbler is a Ruby gem for packaging a Rails application as a Java EE web application. It is built on the Rake build system and JRuby-Rack servlet adapter. The default implementation of the adapter uses a servlet filter that allows the container’s default servlet to process the static content rather than Rails. Early versions of Warbler used the GoldSpike servlet, but the GoldSpike project has been deprecated and has been replaced by JRuby-Rack. The JRuby-Rack library includes a stub version of the GoldSpike servlet in order to maintain compatibility with legacy GoldSpike applications.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using an External Gem Repository with a Web Application
Inhaltsvorschau
You don’t want to package your gems into your web application but want to use a gem repository on the filesystem.
There are a few situations where you might want to use a different gem repository outside of the default JRuby runtime’s repository. This could useful when you are maintaining a shared set of gems that are being accessed by both C Ruby and JRuby. You can configure your web application to use a separate gem repository through the gem.path or gem.home system properties. These properties can be set in the WAR’s file, web.xml, or through a system property when the container is started, as seen in .
Example . Sample web.xml setting the gem.path context parameter
<context-param>

    <param-name>gem.path</param-name>

    <param-value>C:\projects\jruby\jruby-1.1\lib\ruby\gems</param-value>

  </context-param>



  <!-- Alternatively

  <context-param>

    <param-name>gem.home</param-name>

    <param-value>C:\projects\jruby\jruby-1.1\lib\ruby\gems</param-value>

  </context-param>-->
You can also set the gem.path in the startup parameters for the servlet container:
$ java -jar start.jar etc/jetty.xml \

–Dgem.path="C:\projects\jruby\jruby-1.1\lib\ruby\gems"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Configuring the JRuby-Rack Servlet
Inhaltsvorschau
You want to configure the number of JRuby runtimes in the container.
Edit the values in warble.rb to your desired settings:
config.webxml.jruby.min.runtimes = 2

config.webxml.jruby.max.runtimes = 4
Generate the Rails WAR file:
$ jruby –S warble war
The JRuby-Rack servlet allows Rails to integrate into most Java EE containers. Because many parts of Rails prior to version 2.2 are not threadsafe, the runtime cannot be used to simultaneously process multiple requests. JRuby-Rack utilizes a configurable pool of JRuby runtimes that are dispatched for each incoming Rails request. The number of simultaneous requests that can be processed is limited by the number of available runtimes. Any additional requests will block and must wait for a runtime to become free. It’s highly advised that you set a maximum number of runtimes for your production application because by default Warbler will allow for an unlimited number of runtimes. These are all the configuration options:
config.webxml.jruby.max.runtimes
This sets the most number of active JRuby runtimes in the pool, which determines the maximum number of simultaneous requests. Default value is unlimited.
config.webxml.jruby.min.runtimes
This determines the number of “warm” runtimes or the minimum number of runtimes in the pool. It also dictates how many instances when the application is started. The default value is none.
config.webxml.jruby.runtime.initializer.threads
This sets how many threads will be used to initialize the JRuby runtimes in the pool. The value will vary based on the number of runtimes you intend to use at startup and the initialization time of the pool. The default value is 4.
config.webxml.jruby.runtime.timeout.sec
This sets how long in milliseconds an incoming request should wait for a JRuby runtime before returning an error. The default is 30 seconds.
The CPU, memory, and system resources of the host machine generally determine the number of maximum and minimum idle runtimes. The JRuby runtime is a memory-intensive application, so it is recommended to run the application with a generous amount of both permanent generation (PermGen) and heap memory. This is especially true when using a large number of runtimes.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Packaging Rails with a JNDI DataSource
Inhaltsvorschau
You want to configure your Rails application to access a JDBC DataSource through Java Naming and Directory Interface (JNDI).
Install the activerecord-jdbc-adapter gem (as in ) and edit your database.yml file. The JNDI lookup service is provided by the jdbc adapter gem. Set the driver value to your database’s JDBC Driver class and add the JNDI location of the JDBC DataSource. This example database.yml file is configured to use a JDBC factory for a MySQL database:
development:

  adapter: jdbc

  jndi: java:comp/env/jdbc/rails_db

  driver: com.mysql.jdbc.Driver
Use Warbler to package your Rails application (see ). Edit your warble.rb file and set the resource reference name of your JNDI DataSource in the configuration file:
# JNDI data source name

config.webxml.jndi = 'jdbc/rails_db'
Repackage the WAR by running Warbler’s war task:
$ jruby –S warble war
The war or war:webxml tasks create or overwrite an existing Java EE web deployment descriptor file, /WEB-INF/web.xml, in your Warbler staging area, tmp/war. Both tasks add the resource-ref definition and all the required information for a new JDBC . Here is an example web.xml for Rails application using a JNDI DataSource referenced at jdbc/rails_db:
<resource-ref>

    <res-ref-name>jdbc/rails_db</res-ref-name>

    <res-type>javax.sql.DataSource</res-type>

    <res-auth>Container</res-auth>

</resource-ref>
You always have the option of manually editing the files and values generated by Warbler. If you choose to edit the web.xml descriptor file by defining new DataSources or setting configuration values or references, you can use Warbler’s war:jar task to skip the file generation steps and package all the files in the staging folder into the application WAR file:
$ jruby –S warble war:jar
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails on Tomcat
Inhaltsvorschau
You want to deploy a Rails Java EE application using Apache Tomcat.
Package your Rails application as a Java EE WAR (see ). Place the resulting WAR file in the Tomcat’s webapps directory. If you are using one of the database-specific JDBC adapter gems, you’re ready to start Tomcat. If your Rails application is using the regular jdbc adapter, include the JDBC adapter’s JAR file in your classpath or copy the JAR file into $TOMCAT_HOME/common/lib.
Be sure to set the JAVA_HOME environment variable to the folder where you’ve installed Java. A performance tip is to start Tomcat with the -server flag. It is also advisable to set constraints for the heap and PermGen so potential memory leaks do not consume all the resources on the server and cripple the machine.

Windows

> set JAVA_HOME=c:\Program Files\Java\jdk1.5.0_12

> set CATALINA_OPTS=-server –Xms512m –Xmx1024m -XX:PermSize=256m \

  –XX:MaxPermSize=512m

> catalina.bat start

Linux and OS X

$ export JAVA_HOME=/usr/java/jdk1.5.0_12

$ export CATALINA_OPTS='-server –Xms512m –Xmx1024m -XX:PermSize=256m

  –XX:MaxPermSize=512m'

$ ./catalina.sh start
It is important to understand JRuby’s memory usage so that you can properly tune your applications. The JVM has separate memory spaces. One, known as permanent generation (PermGen), is reserved for internal class file representations and VM data structures. The other, heap, is the more known and is typically used to store the data represented in those classes. A lot of JRuby success is owed to the ability to work around the rules of a statically compiled language (i.e., Java) by generating classes and data structures at runtime. The cost of this approach is that in some cases JRuby may need to generate a large number of objects and these objects are all stored in the permanent generation space and not the heap. Consider the case of Rails, where a single request could generate hundreds of JRuby objects. This usage of PermGen is many times the default case, so the default VM memory setting is often insufficient. The JRuby team has made strides in alleviating the problem, such as allowing JRuby runtimes to share PermGen space, but you should take a cautious approach by setting initial and maximum values for your PermGen and heap, especially for production applications.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails on JBoss
Inhaltsvorschau
You want to deploy a Rails application on the JBoss Application Server.
Package your Rails application as a Java EE WAR (see ). Copy the application WAR into $JBOSS_HOME\server\default\deploy, the default JBoss deployment folder, or any server-specific deployment directory you have defined in the JBoss configuration files. If you are using the non-database-specific jdbc adapter for connecting to your database, be sure to include the JDBC JAR in the classpath. You can also copy the JDBC JAR into $JBOSS_HOME\server\default\lib if you’re running the default server.
Be sure to start the application server with the –server flag and set some expected size for your heap and permanent generation, PermGen, memory space. Typically this is done through the JAVA_OPTS environment variable.

Windows

> SET JAVA_HOME=c:\Program Files\Java\jdk1.5.0_12

> SET JAVA_OPTS=-server –Xms512m –Xmx1024m -XX:PermSize=256m –XX:MaxPermSize=512m

> run.bat

Linux and OS X

$ export JAVA_HOME=/usr/java/jdk1.5.0_12

$ export JAVA_OPTS='-server –Xms512m –Xmx1024m -XX:PermSize=256m\

  –XX:MaxPermSize=512m'

$ ./run.sh
If you are using a JNDI resource for your Rails database connection, you will need to create the DataSource in the JBoss server. The JBoss distribution provides sample configurations for most of the popular databases in the examples folder, $JBOSS_HOME\docs\examples\jca. This a great starting place for simple database setups. After you have edited the file, you can easily deploy a DataSource in JBoss by placing the file in the deployment directory. $JBOSS_HOME\server\default\deploy is the deployment folder for the default server.
If you’re running a MySQL database, change the <jndi-name>MySqlDS</jndi-name> configuration parameter to the name of your DataSource, rails_db in this example. Set the rest of database information in the configuration file with the appropriate values for your database. shows an edited mysql-ds.xml DataSource definition for the example application. Note that the
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails on Jetty
Inhaltsvorschau
You want to deploy a Rails application on the Jetty Servlet container.
Package your Rails application as a Java EE WAR (see ). If you’ve defined a JDBC connection with the jdbc adapter or using a JNDI DataSource, remember to include the JDBC adapter in your classpath or copy the JAR into $JETTY_HOME/lib to make it available to any deployed web applications. Place the WAR into Jetty’s $JETTY_HOME/webapp folder. Start the server with the –server VM option and heap and PermGen values:
$ java -server –Xms512m –Xmx1024m -XX:PermSize=256m –XX:MaxPermSize=512m\

  -jar start.jar etc/jetty.xml
If you would like to use a JNDI resource for your Rails database connection, start by defining a DataSource in your WAR. Create a file called jetty-env.xml in the WEB-INF folder of your staging area. shows a jetty-env.xml configuration for a MySQL database.
Example . Sample jetty-env.xml file
<?xml version="1.0"?>

<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"

 "http://jetty.mortbay.org/configure.dtd">



<Configure class="org.mortbay.jetty.webapp.WebAppContext">



  <New id="rails_db" class="org.mortbay.jetty.plus.naming.Resource">

    <Arg>jdbc/rails_db</Arg>

    <Arg>

      <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">

        <Set name="Url">jdbc:mysql://localhost:3306/jrubycookbook_development</Set>

        <Set name="User">root</Set>

        <Set name="Password">password</Set>

     </New>

    </Arg>

   </New>

</Configure>
Repackage your application with Warbler and deploy to Jetty. Jetty’s JNDI module is not enabled in the standard webapps deployment folder by default, so either update $JETTY_HOME/etc/jetty.xml to enable JNDI for this directory or configure Jetty to use an alternative directory. It is the Jetty convention to install applications that require JNDI into the webapps-plus directory:
$ copy MyKillerApplication.war $JETTY_HOME/webapps-plus
Jetty supplies a convenient $JETTY_HOME/etc/jetty-plus.xml file, which configures Jetty to use that folder. Run this command from the Jetty home directory to start Jetty with JNDI support:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails with jetty_rails
Inhaltsvorschau
Many Rails developers today have never worked with the Java EE packaging process and launch their applications by navigating to the top level of their Rails project and starting one of two popular Ruby web servers: Mongrel or WEBrick. You want to run the Jetty application server with your Rails application but use a deployment method more familiar to Rails developers.
Use the jetty_rails gem, which allows you to run a Rails application with the Jetty server without performing any Java EE packaging. First, install the jetty_rails gem:
jruby –S gem install jetty_rails
Then, go to the top of your Rails application and start the Jetty server:
$ cd jrubycook_application

$ jruby -S jetty_rails
You can get a list of some common startup parameters by running this command:
jruby –S jetty_rails --help
The port and environment options are common startup parameters used in the Mongrel and WEBrick HTTP servers:
  • Pass in the --port <port> or –p <port> parameter to set the port of your web . The default is 3000.
  • Use the --environment <env> or –e <env> to specify the Rails execution environment. The default value is development.
  • Set the --context-path <path> or –u <path> parameter to change your applications context root. Remember to make your Rails application aware of this change of code to your environment.rb file:
    ActionController::AbstractRequest.relative_url_root = "/my_new_context_root"
  • Use the –c or --config parameter to load the server configuration through an external file. The server will look in the default location, config/jetty_rails.yml, if you do not include a file path.
The configuration file is valuable beyond the organizational benefit of getting the startup parameters out of the input arguments. As of version 0.6, you can use the file to tune your application by setting JRuby and Jetty configuration values, leverage a layered configuration system, and run multiple Rails applications within a single Jetty instance.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails with Mongrel
Inhaltsvorschau
You want to run a JRuby on Rails application with Mongrel.
Install the Mongrel gem. The JRuby gem installer should select the latest Java version of the gem:
$ jruby –S gem install mongrel –-no-ri –-no-rdoc

Updating metadata for 165 gems from http://gems.rubyforge.org

......................................................................

complete

Successfully installed gem_plugin-0.2.3

Successfully installed mongrel-1.1.4-java

2 gems installed
Include the JDBC adapter of your database in your classpath if you aren’t using the database-specific jdbc adapter that packages and loads the driver. Go to your Rails application’s home directory and start Mongrel:
$ jruby –S mongrel_rails start

** Starting Mongrel listening at 0.0.0.0:3000

** Starting Rails with development environment...

** Rails loaded.

** Loading any Rails specific GemPlugins

** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).

** Rails signals registered.  HUP => reload (without restart).  It might not wor

k well.

** Mongrel 1.1.4 available at 0.0.0.0:3000

** Use CTRL-C to stop.
Mongrel is a small but high-performance web server originally written in Ruby and C. Recently, the C portions have been ported to Java so that Mongrel can run under JRuby. This was an important milestone for the project given that many Rails developers use Mongrel in their production and development environments.
There is an experimental gem to provide clustering support for the Java version of Mongrel called mongrel_jcluster. Unfortunately, this gem is currently only supported on Linux, OS X, and Cygwin on Windows. The default Windows DOS shell is currently not yet supported. This gem allows you easily start and stop sets of Mongrel servers and attempts to recreate some of the functionality of mongrel_cluster, which is incompatible with JRuby. First, install the gem:
$ jruby –S gem install mongrel_jcluster

Successfully installed mongrel_jcluster-0.0.1

1 gem installed
Next, generate a configuration file for your Mongrel cluster:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying Rails on the GlassFish v2 Server
Inhaltsvorschau
You want to deploy a Rails application on the GlassFish v2 application server.
Install the GlassFish server and navigate to the home directory. Set up the deployment area and configure the server with the supplied ant task:
$ $GLASSFISH_HOME/lib/ant/bin/ant -f setup.xml
This will install several libraries and create your Java EE application deployment folder at $GLASSFISH_HOME\domains\domain1\autodeploy. Package your Rails application as a Java EE WAR (see ). If you’ve defined a JDBC connection with the jdbc adapter or using a JNDI DataSource, remember to include the JDBC adapter in your classpath or copy the JAR file into $GLASSFISH_HOME/lib to make it available to your web applications.
Start the server with this command:
$ $GLASSFISH_HOME/bin/asadmin start-domain
Wait a few seconds after the server starts to allow enough time to deploy your Rails WAR ().
Figure : Starting up the GlassFish server
Open your browser to http://localhost:8080/MyKillerApplication to view your Rails project.
Rails applications that use a JNDI DataSource can use the asadmin command with input parameters to define the DataSource’s properties. This example creates a connection pool for a MySQL server at our standard example address jdbc/rails_db:
$ $GLASSFISH_HOME\bin\asadmin create-jdbc-connection-pool –datasourceclassname \

 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource \

 --restype javax.sql.DataSource –property User=root:Password=password:\

 URL=jdbc\:mysql\://localhost:3316/jrubycookbook_development jdbc/rails_db

Command create-jdbc-connection-pool executed successfully.
Next, make the new DataSource available to your Rails WAR and other Java EE installed on the server:
$ $GLASSFISH_HOME\bin\asadmin create-jdbc-resource --connectionpoolid \

 jdbc/rails_db jdbc/rails_db

Command create-jdbc-resource executed successfully.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the GlassFish v3 Gem
Inhaltsvorschau
You want to run a Rails application with the GlassFish v3 gem.
First, install the GlassFish v3 gem:
$ jruby –S gem install glassfish

 Successfully installed glassfish-0.1.2-universal-java

 1 gem installed
Start your Rails application with the new glassfish_rails command. You currently have to start the server in the directory that contains your Rails application directory:
$ jruby -S glassfish_rails MyKillerApplication
Open your browser to http://localhost:3000 and you should see the Rails welcome screen.
The GlassFish v3 server is Sun’s latest effort to build a widely adopted Java EE server. They have packaged this server as a Ruby gem and configured it to run Rails with a few simple commands.
The gem implements a pool of JRuby runtimes that work a lot like the pooling used in the GoldSpike servlet. You can set the number of JRuby runtimes in the pool by using the –n or the --runtimes flag when starting the server. The following examples will start up servers with three runtimes in each pool:
$ jruby –S glassfish_rails MyKillerApplication –n 3
or:
$ jruby –S glassfish_rails MyKillerApplication –-runtimes 3
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using ActiveRecord Outside of Rails
Inhaltsvorschau
You want to use ActiveRecord as the Object-Relational Mapping (ORM) solution for a non-Rails application.
If you have not installed Rails, install the activerecord gem:
$ jruby -S gem install activerecord --no-ri --no-rdoc
Install the activerecord-jdbc-adapter gem, which will provide access to the database through a JDBC connection:
$ jruby -S gem install activerecord-jdbc-adapter --no-ri --no-rdoc
Include your database’s JDBC adapter in your classpath or JRuby lib folder if you’re not using a database-specific adapter. For example, to connect to a MySQL database, you will need the activerecord-jdbcmysql-adapter gem. See for more about database-specific drivers and gems.
$ jruby -S gem install activerecord-jdbcmysql-adapter --no-ri --no-rdoc
Create a YAML file called database.yml such as the one in to define your database connection parameters.
Example . Sample database.yml file
development:

  adapter: jdbcmysql

  database: jrubycookbook_development

  host: localhost

  port: 3306

  username: root

  password: password
Once this setup is in place, you can load the file and establish a connection to one of the databases defined in it. In , we load the development database defined in the configuration file from . Once the database connection has been established, we run a query and iterate through the results. Finally, we utilize one of the dynamic finder methods that are attached to objects by the ActiveRecord .
Example . Loading a database.yml file and accessing the database
require 'rubygems'

gem 'activerecord-jdbcmysql-adapter'

require 'active_record'

require 'yaml'



@connections = YAML.load_file("database.yml")

ActiveRecord::Base.establish_connection(@connections["development"])



stmt = "select id, title from games"

@val = ActiveRecord::Base.connection.select_all(stmt)

@val.each do |g|

      puts "game id: #{g["id"]} #{g["title"]}"

end



class Game < ActiveRecord::Base

end



puts "found game id: #{Game.find(1).id}"
This is the output of the program:
$ jruby games.rb

game id: 1 Alien Invasion

looking up game id: 1
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Accessing Common Java Servlet Information
Inhaltsvorschau
You want to access the Java servlet request object from your Rails controllers.
JRuby-Rack’s servlet filter makes several servlet variables available to the Rails application on each incoming request. Access the standard javax.servlet.ServletRequest through the Rack environment map with the key java.servlet_request. The ServletContext object can also be fetched through the Rack environment hash with the java.s⁠e⁠r⁠v⁠let_context key, or through the global variable, $servlet_context. shows a controller that uses some of these variables.
Example . Accessing the Java servlet objects from a Rails controller
class HelloWorldController < ApplicationController

      def hello

        ctx = request.env['java.servlet_context']

        puts "server info: #{ctx.server_info}"

        puts "server info: #{$servlet_context.server_info}"



        req = request.env['java.servlet_request']

        puts "uri: #{req.request_uri}"

        puts "query string: #{req.query_string}"

        puts "port: #{req.server_port}"

        puts "param hello: #{req.get_parameter("hello")}"

        puts "session id: #{req.get_session.id}"

      end

end
Accessing http://localhost:3000/MyKillerApplication/hello?hello=world would output these messages to the container’s log file:
server info: jetty-6.1.9

server info: jetty-6.1.9

uri: /hello_world/hello

query string: hello=world

port: 3000

param hello: world

session id: 2026
JRuby-Rack does not provide access to the ServletResponse object from within your controller. This feature was available in earlier versions of Warbler through the GoldSpike servlet but has been removed after the integration of JRuby-Rack.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Configuring Session Storage
Inhaltsvorschau
You want to configure the session storage mechanism used by your Rails application.
Edit the web.xml file in your web application and set the jruby.session_store context parameter to db by adding this bit of code:
<context-param>

       <param-name>jruby.session_store</param-name>

       <param-value>db</param-value>

       <!-- This value really means let Rails take care of session store -->

</context-param>
By default, JRuby-Rack’s servlet filter uses the Java EE servlet container’s session storage. Changing the jruby.session_store context parameter to db tells JRuby-Rack to defer to Rails’s session management.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Controlling the Classes, Directories, and Other Files Packaged into a Rails WAR File
Inhaltsvorschau
There are classes and other files you want to include and/or exclude from your WAR file.
Open the Warbler configuration file config/warbler.rb and validate these configuration options:
# Application directories to be included in the webapp.

config.dirs = %w(app config lib log vendor tmp)



# Additional files/directories to include, above those in config.dirs

config.includes = FileList["db"]



# Additional files/directories to exclude

config.excludes = FileList["lib/tasks/*"]



# Additional Java .jar files to include.  Note that if .jar files are placed

# in lib (and not otherwise excluded) then they need not be mentioned here

# JRuby and JRuby-Rack are pre-loaded in this list.

# Be sure to include your own versions if you directly set the value

config.java_libs += FileList["lib/java/*.jar"]



# Loose Java classes and miscellaneous files to be placed in WEB-INF/classes.

config.java_classes = FileList["target/classes/**.*"]



# One or more pathmaps defining how the java classes should be copied into

# WEB-INF/classes. The example pathmap below accompanies the java_classes

# configuration above. See http://rake.rubyforge.org/classes/String.html#M000017

# for details of how to specify a pathmap.

config.pathmaps.java_classes << "%{target/classes/,}"
By default, Warbler will include the JRuby runtime and JRuby-Rack in the WAR files it produces. There are some cases where you might prefer to install these JARs in a shared library area rather than packaging the JAR files with each web application. The shared packaging approach can accomplish this, but some developers may want a mixed approach, in which the packaged WAR file includes dependent gems but not the JRuby runtime and the JRuby-Rack servlet. The config.java_libs property is simply a Ruby array, so you can use well-known array operations to exclude items from Warbler’s build process. For example, you can use the reject! method with a regular expression to exclude all versions of JRuby and JRuby-Rack from the final WAR file:
config.java_libs.reject! {|lib| lib =~ /jruby-complete|jruby-rack/ }
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Changing the Name of the WAR File and the Staging Area
Inhaltsvorschau
You want to change the name of the WAR file and/or Warbler’s staging area.
By default, Warbler will name the generated WAR file according to the Rails application’s directory name. You can customize the name by setting the config.war_name parameter in your config/warbler.rb configuration file:
# Name of the war file (without the .war) -- defaults to the basename

# of RAILS_ROOT

config.war_name = "mywar"
You may also want to modify the staging folder that contains the decompressed source files for the final WAR. In warbler.rb, set the config.staging_dir to your target staging folder:
# Temporary directory where the application is staged

config.staging_dir = "tmp/war"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Deploying a Rails Application to the Root Context
Inhaltsvorschau
You want to make your Java EE web application available from the root context of the servlet container.
In general, the simplest approach is to package your Rails application with the name ROOT.war. This can be configured using the Warbler configuration file, warble.rb:
config.war_name = "ROOT"
Before deploying this WAR file, be sure to remove any existing directories named ROOT or ROOT.war files from your container’s deployment directories.
Although not actually part of the Java EE standard, using a filename of ROOT.war to indicate to the servlet container that you want this application to be deployed in the root context is a widely used convention. Each container defines a custom deployment descriptor. We’ve seen examples of these descriptors in previous recipes. If you are using JNDI DataSources, you will need to modify the deployment descriptors to match the context name.

Tomcat

Edit the context.xml file in the META-INF directory in your staging area (see ). Set the path and docBase attributes to / (). Warbler does not create this file by default so you will have to create it yourself and repackage the WAR.
Example . Changing the context path for a Tomcat deployment
<Context path="/" docBase="/" debug="5" reloadable="true" crossContext="true">



    <Resource name="jdbc/rails_db" auth="Container" type="javax.sql.DataSource"

               maxActive="100" maxIdle="30" maxWait="10000"

               username="root" password="password"

               driverClassName="com.mysql.jdbc.Driver"

url="jdbc:mysql://localhost:3306/jrubycookbook_development?autoReconnect=true"/>



</Context>

JBoss

Edit the jboss-web.xml file in the WEB-INF directory in your staging area (see ). Change the context-root value to / (). Warbler does not create this file by default so you will have to create it yourself and repackage the WAR.
Example . Changing the context path for a JBoss deployment
<jboss-web>

    <context-root>/</context-root>

    <resource-ref>

        <res-ref-name>jdbc/rails_db</res-ref-name>

        <res-type>javax.sql.DataSource</res-type>

        <jndi-name>java:rails_db</jndi-name>

    </resource-ref>

</jboss-web>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating a Rails Application with Aptana Studio
Inhaltsvorschau
You want to create a Rails application using Aptana Studio.
Download and install the Aptana Studio software from the Aptana website, http://www.aptana.com/download. Open the Aptana start page at Help→Aptana Studio Start Page and scroll to the RadRails information in the Plugins column. Click on the Install button on the start page and complete the installation wizard. You can also install the plugin by selecting the RadRails item in the Plugin Manager, located in a tab in the bottom frame, and clicking on the installation icon. Both options are shown in .
Figure : Aptana Studio: RadRails installation options
Aptana is built on the Eclipse IDE platform. As a result, the solution from should be followed to set up the JRuby runtime and other common Eclipse configuration options. Once configuration is complete, choose the RadRails perspective by clicking on the new RadRails icon or select Other→RadRails in the perspectives menu in the top right corner of the window. Create your new Rails application by selecting File→New→Rails Project in the menu. Give the project a name and choose your database platform from the available options. Click Finish, and RadRails will generate the files for your Rails application, which are shown in the left Rails File window. The default wizard settings will also create and start a Mongrel server instance. The editor should be displaying the Aptana welcome screen shown in . Open the Rails database configuration file at config/database.yml in the left Explorer window and edit the values for your database. You can start and stop your Mongrel server by navigating to the Servers tab found in the bottom center window. Select your Rails application in the list and use the controls to start the server in regular or debug mode.
Figure : RadRails Interface and Welcome screen
The Rails Shell was introduced with RadRails version 1.0 and gives the developer access to Rails commands through a command-line interface. Choose the Console tab in the bottom panel or choose Open a Rails Shell in the console options. The shell and the location of the options button are shown in . The Rails Shell complements the graphical interfaces for performing common Rails tasks and brings the IDE more in line with the Rails developers’ preference of administering their application through a shell interface. The Rails Shell allows you to execute generator scripts, Rake tasks, and migrations, and create Rails projects and install gems and plugins.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Accessing Static Files in Your Rails Java EE Application
Inhaltsvorschau
Warbler packages your Rails application by separating the static content from the executable code and moving it into the top-level directory in the WAR. This creates problems for some Rails functions such as render :file because the file paths it is generating are now incorrect. You would like your Rails application to serve static content in both a standard deployment and when assembled using Warbler.
Add a hook into your Rails application by creating a public_dir.rb file in the initializers directory. Evaluate the $servlet_context variable, which is only set when running in a Java EE environment, and set the location of the public directory based on the existence of the variable. shows a technique for toggling the public directory.
Example . Public directory detection code
PUBLIC_DIR = if defined?($servlet_context)

     $servlet_context.getRealPath('/')

   else

     "#{RAILS_ROOT}" + '/public'

   end
Replace all the calls in your Rails code from render :file => "/public/data/jobs.log" to render :file => "#{PUBLIC_DIR}/data/jobs.log".
You will also need to patch Rails’ internal functions that build paths to static files. The render_optional_error_file in ActionController can be patched by adding the code in to your Rails application.rb file. A new module with patched method is mixed into the original ActionController module at runtime.
Example . Patching functions that serve static files
module Cookbook

 module PublicRescueExtensions

   protected

   def render_optional_error_file(status_code)

     status = interpret_status(status_code)

     path = "#{PUBLIC_DIR}/#{status[0,3]}.html"

     if File.exists?(path)

       render :file => path, :status => status

     else

       head status

     end

   end

 end

end

ActionController::Rescue.send :include,

  Cookbook::PublicRescueExtensions
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 3: Java Integration
Inhaltsvorschau
The first two chapters examined JRuby almost entirely from a Ruby-centric perspective. In the next few chapters, we look at leveraging JRuby more as a toolkit for Ruby and Java integration. There are two primary integration approaches that we will explore in this chapter. The first is how JRuby can be used to add functionality to a Java application; the second is how Ruby programs can take advantage of the wide array of Java libraries. Frequently, these types of integration are combined. For , when mixing Java and Ruby code, using a consistent configuration for logging can be useful, something which is explored in .
There are three primary APIs for embedding Ruby into a Java application:
  • The JRuby low-level API
  • The Bean Scripting Framework (BSF)
  • Java Scripting, defined by JSR 223
These APIs are the subject of the first three recipes in this chapter. The differences between the low-level API and either BSF or Java Scripting are fairly obvious—the low-level API ties your Java code directly to JRuby, whereas both BSF and Java Scripting are abstractions of the JRuby runtime and, in fact, support multiple scripting languages. In general, you will use the JRuby API when you need tight control over the runtime’s configuration. The choice between BSF and Java Scripting is largely based on deployment environment—BSF support is more consistent on Java 5, whereas Java Scripting is only available as a backport.
Regardless of the mechanics, the value of using JRuby in this way primarily stems from the fact that Ruby code is interpreted, not compiled. This allows you to store Ruby code in a Java String object and evaluate it while your application is running. For , a reporting application could store the Ruby code necessary to generate a report in a database. Another scenario would be to have an application through Ruby-based plugins that could be added or removed while the is running, something not typically associated with Java applications. A technique has been used extensively in gaming, most notably the popular, massive multiplayer game World of Warcraft, which can be extended by users using the Lua scripting language (even though the core is written in C++).
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
The first two chapters examined JRuby almost entirely from a Ruby-centric perspective. In the next few chapters, we look at leveraging JRuby more as a toolkit for Ruby and Java integration. There are two primary integration approaches that we will explore in this chapter. The first is how JRuby can be used to add functionality to a Java application; the second is how Ruby programs can take advantage of the wide array of Java libraries. Frequently, these types of integration are combined. For , when mixing Java and Ruby code, using a consistent configuration for logging can be useful, something which is explored in .
There are three primary APIs for embedding Ruby into a Java application:
  • The JRuby low-level API
  • The Bean Scripting Framework (BSF)
  • Java Scripting, defined by JSR 223
These APIs are the subject of the first three recipes in this chapter. The differences between the low-level API and either BSF or Java Scripting are fairly obvious—the low-level API ties your Java code directly to JRuby, whereas both BSF and Java Scripting are abstractions of the JRuby runtime and, in fact, support multiple scripting languages. In general, you will use the JRuby API when you need tight control over the runtime’s configuration. The choice between BSF and Java Scripting is largely based on deployment environment—BSF support is more consistent on Java 5, whereas Java Scripting is only available as a backport.
Regardless of the mechanics, the value of using JRuby in this way primarily stems from the fact that Ruby code is interpreted, not compiled. This allows you to store Ruby code in a Java String object and evaluate it while your application is running. For , a reporting application could store the Ruby code necessary to generate a report in a database. Another scenario would be to have an application through Ruby-based plugins that could be added or removed while the is running, something not typically associated with Java applications. A technique has been used extensively in gaming, most notably the popular, massive multiplayer game World of Warcraft, which can be extended by users using the Lua scripting language (even though the core is written in C++).
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Executing Ruby from Java
Inhaltsvorschau
You want to execute some Ruby code from a Java application.
Obtain an instance of org.jruby.Ruby and call the evalScriptlet() method. The org.jruby.javasupport.JavaEmbedUtils class provides static factory methods for creating an instance of the JRuby runtime. shows a simple usage of these classes.
Example . Calling Ruby from Java
package org.jrubycookbook.ch03;



import java.util.Collections;



import org.jruby.Ruby;

import org.jruby.javasupport.JavaEmbedUtils;



public class RubyRunner {



    public static void main(String[] args) {

        // Create an instance of the JRuby runtime. The parameter to initalize()

        // is a list of paths to be added to the Ruby load path.

        Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST);

        runtime.evalScriptlet("puts 'hello world'");

    }



}
When run, this class outputs the classic greeting:
hello world
Prior to JRuby 1.0.3, the method used to obtain instances of the JRuby runtime was Ruby.getDefaultInstance(). Although this usage has been deprecated, you may see it from time to time in code examples.
Every execution of JavaEmbedUtils.initialize() will create a new instance of the JRuby runtime. JRuby also provides a mechanism for reuse of JRuby runtimes within a single Java thread. To enable this, set the Java system property jruby.runtime.threadlocal to "true". If this is set, calls to JavaEmbedUtils.initialize() will create a new instance and store that instance in a ThreadLocal variable. To access this instance, call Ruby.getCurrentInstance(). illustrates instance reuse by setting and retrieving a global variable within the runtime.
Example . Using the current JRuby runtime
package org.jrubycookbook.ch03;



import java.util.Collections;



import org.jruby.Ruby;

import org.jruby.javasupport.JavaEmbedUtils;



public class RubyRunner2 {



    public static void main(String[] args) {

        // Enable ThreadLocal support

        System.setProperty("jruby.runtime.threadlocal", "true");

        // Create a JRuby instance

        Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST);

        // Execute a bit of Ruby code that creates a variable

        runtime.evalScriptlet("$message = 'hello world from JRuby'");

        runtime.evalScriptlet("$counter = 0");

        for (int i = 0; i < 5; i++) {

            outputMessage();

        }

    }



    private static void outputMessage() {

        Ruby runtime = Ruby.getCurrentInstance();

        String scriptlet = "puts \"<#{$counter}> #{$message}\"";

        runtime.evalScriptlet("$counter = $counter.next");

        runtime.evalScriptlet(scriptlet);

    }

}
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Invoking JRuby Through the Bean Scripting Framework
Inhaltsvorschau
You want to execute some Ruby code from a Java application and want the flexibility to support multiple scripting language implementations.
Use the Bean Scripting Framework (BSF):
  1. Add bsf.jar, included with JRuby distributions, to your Java classpath.
  2. Register the JRuby scripting engine with the BSF runtime.
  3. Create an instance of the org.apache.bsf.BSFManager class.
  4. Call the eval() or exec() method on the BSFManager object.
shows a simple usage of JRuby through BSF.
Example . Invoking JRuby with BSF
package org.jrubycookbook.ch03;



import org.apache.bsf.BSFException;

import org.apache.bsf.BSFManager;



public class RubyBSFRunner {



    public static void main(String[] args) throws BSFException {

        BSFManager.registerScriptingEngine("ruby",

                "org.jruby.javasupport.bsf.JRubyEngine", new String[] { "rb" });

        BSFManager manager = new BSFManager();

        manager.exec("ruby", "<script>", 1, 1, "puts 'hello world'");

    }



}
The Bean Scripting Framework is an open source software framework originally by IBM that is now part of the Apache Jakarta project. It provides a generic application programming interface (API) for supporting scripting languages within Java applications. BSF comes with built-in support for several scripting languages, :
  • JavaScript
  • NetRexx
  • Python
  • Tcl
  • XSLT
In addition to these languages, the Bean Scripting Framework defines a service provider interface (SPI) that allows other scripting languages to be plugged in by implementing the org.apache.bsf.BSFE⁠n⁠gine interface. JRuby provides an implementation of this interface with the class org.jruby.javasupport.bsf.JRubyEngine. As you can see in , it is necessary to register this class with BSF by calling BSFManager.registerScriptingEngine(). When registering this engine implementation (or any other), you have to provide BSF with both the name of the scripting language (ruby) and a list of possible file extensions (rb). BSFManager provides two methods for invoking a scripting language:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Invoking JRuby Through Java Scripting Support
Inhaltsvorschau
You are running Java 6 (or later), and you want to execute some Ruby code from a Java application and want the flexibility to support multiple scripting language .
Use Java’s built-in scripting framework, defined in JSR (Java Specification Request) 223:
  1. Download jsr223-engines.zip from https://scripting.dev.java.net.
  2. Unzip the file jruby/build/jruby-engine.jar from jsr223-engines.zip and add it to your classpath.
  3. Create an instance of javax.script.ScriptEngineManager.
  4. Call getEngineByName("ruby") to obtain an instance of javax.script.ScriptEngine.
  5. Call the eval() method on the ScriptEngine object.
shows a simple usage of JRuby using the JSR 223 API.
Example . Invoking JRuby through javax.script.ScriptEngineManager
package org.jrubycookbook.ch03;



import javax.script.ScriptEngine;

import javax.script.ScriptEngineManager;

import javax.script.ScriptException;



public class Ruby223Runner {



    public static void main(String[] args) throws ScriptException {

        ScriptEngineManager scriptManager = new ScriptEngineManager();

        ScriptEngine engine = scriptManager.getEngineByName("ruby");

        engine.eval("puts 'hello world'");

    }



}
JSR 223: Scripting for the Java Platform was one of the more highly anticipated upgrades to the Java platform in the Java 6 release. At the simplest level, it provides a standardized version of the API (and SPI) that the Bean Scripting Framework (BSF) had provided for many years. Almost more importantly, however, is the message that JSR 223 sends to the programming community as a whole by formalizing the distinction between Java the language and Java the platform. JSR 223’s mere existence suggests that the Java platform will provide a suitable runtime environment for a variety of scripting languages, including Ruby/JRuby.
As you can see by comparing with , the JSR 223 API is simpler to use than the BSF API in that proactive registration of scripting engines is not required. JSR 223 defines a discovery mechanism that allows script engines to be automatically discovered based on the existence of a file in the
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Logging from Ruby with Jakarta Commons Logging
Inhaltsvorschau
You are running Ruby code within a Java application that uses Jakarta Commons Logging (JCL) and wish your log messages to be consistent.
Use a class like the one in to transform fully qualified Ruby class names into identifiers that resemble fully qualified Java class names.
Example . Custom JRuby LogFactory bridge class
package org.jrubycookbook.ch03;



import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;



import org.jruby.RubyObject;



public class JRubyLogFactory {

    public static Log getLog(RubyObject o) {

        String rubyClassName = o.getMetaClass().getName();

        String logName = rubyClassName.replace("::", ".");

        return LogFactory.getLog(logName);

    }

}
Once this is in place, you can reference this class in your Ruby code and create new Log objects by passing self to the getLog() method. Log messages will be logged under a log name derived from the fully qualified Ruby class name. The script in will log a message under the log name Log.LogTest.
Example . Using the JRubyLogFactory bridge class
include Java



import org.jrubycookbook.ch03.JRubyLogFactory



module Log

    class LogTest

        def initialize

            @log = JRubyLogFactory.getLog(self)

        end



        def hello

            @log.info("hello via jcl")

        end

    end

end



Log::LogTest.new.hello
Jakarta Commons Logging is a popular Java library for providing a consistent logging API across several logging implementations, including Log4J, the java.util.logging package, LogKit, and JCL’s own SimpleLog. JCL is especially popular amongst library developers as it allows the library to work with several logging implementations without having a compile-time dependency to any of them. Java code will typically obtain an implementation of the org.apache.commons.logging.Log interface by calling one of two factory methods:
  • LogFactory.getLog(Class)
  • LogFactory.getLog(String)
The former calls the latter passing the fully qualified class name. As many logging packages allow you to configure logging using a hierarchal model, i.e., all logs whose names begin with
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the Java Concurrency Utilities
Inhaltsvorschau
You want to use the classes in the java.util.concurrent package to write code that is both thread-safe and highly performant.
Simply reference the classes in your Ruby code. For example, to create an instance of java.util.concurrent.ConcurrentHashMap, just use the constructor:
$hash = java.util.concurrent.ConcurrentHashMap.new
Likewise, the java.util.concurrent.Executors factory class can be used to create powerful yet easy-to-use thread pools. In , a thread pool containing two threads is created and used from Ruby code.
Example . Using a java.util.concurrent thread pool from Ruby
include Java



class MyLongTask

    include java.util.concurrent.Callable



    def initialize(label)

        @label = label

    end



    def call

        puts "about to sleep in task labeled #{@label}\n"

        # artificially create a longer delay

        sleep 5

        puts "done sleeping in task labeled #{@label}\n"

        return "result of the long task labeled #{@label}\n"

    end

end



# create a new thread pool

executor = java.util.concurrent.Executors::newFixedThreadPool(2)



# create an array to store the future value references

future = Array.new



puts "submitting first task"

future[0] = executor.submit(MyLongTask.new("first"))



puts "submitting second task"

future[1] = executor.submit(MyLongTask.new("second"))



puts "submitting third task"

future[2] = executor.submit(MyLongTask.new("third"))



puts "All tasks have been submitted"



# this method call will block until the first task has completed

puts future[0].get()



# this method call will block until the second task has completed

puts future[1].get()



# this method call will block until the third task has completed

puts future[2].get()
The exact output of this code may vary slightly from execution to execution, but in general you will see all three tasks being submitted, followed by the first two tasks starting to sleep. Eventually, those tasks will complete and the third will start. However, since there are multiple threads, the first two tasks may be completed in any order, as seen here:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating JavaBean Style Accessor Methods
Inhaltsvorschau
Ruby developers use the attr_accessor function as a convenient way to declare instance variables and create read and write methods in a class. You would like a similar function that can add JavaBean-style get and set methods to a class with a condensed and syntax.
Start by creating a Ruby module that will contain the new method. The function can be coded directly into your classes, but the module encourages more reusable and less repetitive code. Create a method called java_attr_accessor that accepts a list of symbols, consistent with Ruby’s attr_accessor method. The symbols are named with the Ruby style of using underscores as word delimiters, but the function will convert each symbol into the JavaBean-style equivalent name by adding the get and set prefixes to the camel case representation of the name. shows the module and a class that adds several instance variables using the java_attr_accessor method after extending the new module.
Example . Helper module for JavaBean accessors
module Helper

  def java_attr_accessor(*symbols)

    symbols.each { |symbol|

      camelcased = symbol.to_s.capitalize.gsub(/\_[a-zA-Z]/) {|s| s[1..1].upcase}

      module_eval( "def get#{camelcased}() @#{symbol}; end" )

      module_eval( "def set#{camelcased}(val) @#{symbol} = val; end" )

    }

  end

end



class Example

        extend Helper

        java_attr_accessor :title,:first_name

end



mc = Example.new

mc.setTitle('Cookbook')

mc.setFirstName("John")
This utility function can be very useful when working with applications or frameworks that make heavy use of JavaBeans, such as Hibernate and Spring.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Writing Consistent Code
Inhaltsvorschau
You are calling both Ruby and Java libraries from Ruby and want the code to look consistent. This line from is very obviously calling a Java method:
@log = JRubyLogFactory.getLog(self)
Replace camel-cased method names with method names that follow the Ruby naming convention: all lowercase letters and underscores for word separators. The line from referenced above could be rewritten as:
@log = JRubyLogFactory.get_log(self)
JRuby provides this automatic method translation as a way of blending Java and Ruby method calls together.
JRuby won’t override an existing method. If there was an actual method named get_log(), it takes precedence. That caveat aside, using this feature leads to a more consistent coding style.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Transforming XML with TrAX
Inhaltsvorschau
You want to transform XML documents using XSLT through Java’s Transformation API for XML (TrAX).
Import the class javax.xml.transform.TransformerFactory as well as the classes to be used for the input and output, typically javax.xml.transform.stream.StreamSource and javax.xml.transform.stream.StreamResult. If you will be transforming with the same stylesheet repeatedly, create a javax.xml.transform.Templates object to save the stylesheet. If this is a one-time transformation, simply create a javax.xml.t⁠r⁠a⁠n⁠s⁠f⁠o⁠r⁠m.Transformer object. shows both scenarios.
Example . Using TrAX from JRuby
include Java



import javax.xml.transform.TransformerFactory

import javax.xml.transform.stream.StreamResult

import javax.xml.transform.stream.StreamSource



# Create a new TransformerFactory instance

factory = TransformerFactory.new_instance



# Compile a stylesheet into a Template object

style_input = StreamSource.new("rss.xslt")

templates = factory.new_templates(style_input)



# Setup sources for input and output

input = StreamSource.new("http://www.mtv.com/rss/news/news_full.jhtml")

output = StreamResult.new(java.lang.System.out)



# Create a new Transformer from the Template object

transformer = templates.new_transformer



# Do the transformation

transformer.transform(input, output)



# Simplified – just create a new Transformer from the stylesheet

transformer = factory.new_transformer(style_input)

transformer.transform(input, output)
TrAX includes a few interfaces that can be easily implemented in Ruby to customize the transformation process. The interface javax.xml.transform.ErrorListener receives callbacks from the Transformer object whenever a warning or error is encountered. shows a simple implementation of this interface in Ruby.
Example . Implementing javax.xml.transform.ErrorListener in Ruby
class ErrorCounter

  attr_reader :errors

  attr_reader :warnings

  attr_reader :fatals



  def error(ex)

    @errors = 0 if (@errors == nil)

    @errors = @errors + 1

  end



  def warning(ex)

    @warnings = 0 if (@warnings == nil)

    @warnings = @warnings + 1

  end



  def fatalError(ex)

    @fatals = 0 if (@fatals == nil)

    @fatals = @fatals + 1

  end

end



# Use the ErrorCounter class

counter = ErrorCounter.new

transformer = factory.new_transformer(style_input)

transformer.error_listener = counter

transformer.transform(input, output)



p "Errors: #{counter.errors}"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating a Pool of JRuby Runtimes
Inhaltsvorschau
You need to execute Ruby code that is not thread-safe and requires exclusive control of the JRuby runtime and do not want to create new runtimes per thread.
Use the Jakarta Commons Pool library to create a pool of JRuby runtimes. When your code needs to invoke JRuby, borrow a runtime from the pool and return it when . To start, download Jakarta Commons Pool from http://jakarta.apache.org/commons/pool/ and add the JAR file to your classpath. Create a subclass of org.apache.commons.pool.BasePoolableObjectFactory that creates JRuby runtimes using the methods in . Then use this factory object to construct an org.apache.commons.pool.impl.GenericObjectPool. shows a subclass of GenericObjectPool built for pooling JRuby runtimes.
Example . Creating a pool of JRuby runtimes
package org.jrubycookbook.ch03;



import java.util.Collections;

import java.util.Date;



import org.apache.commons.pool.BasePoolableObjectFactory;

import org.apache.commons.pool.impl.GenericObjectPool;

import org.jruby.Ruby;

import org.jruby.javasupport.JavaEmbedUtils;



public class JRubyRuntimePool extends GenericObjectPool {



    private static class JRubyRuntimeFactory extends BasePoolableObjectFactory {



        public Object makeObject() throws Exception {

            Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST);

            return runtime;

        }



    }



    public JRubyRuntimePool() {

        super(new JRubyRuntimeFactory());

    }



    public Ruby borrowRuntime() throws Exception {

        return (Ruby) borrowObject();

    }



    public void returnRuntime(Ruby runtime) throws Exception {

        returnObject(runtime);

    }



    public static void main(String[] args) throws Exception {

        JRubyRuntimePool pool = new JRubyRuntimePool();

        // always have a minimum of five runtimes available in the pool.

        pool.setMinIdle(5);



        // if there are more than 10 runtimes in the pool, remove the extras

        pool.setMaxIdle(10);



        // and don't allow more than 40 runtimes to be in use at the same time

        pool.setMaxActive(40);



        // check every minute that the minimum and maximum idle counts are met

        pool.setTimeBetweenEvictionRunsMillis(60000);



        // start the application

    }

}
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Performing Remote Management with JMX
Inhaltsvorschau
You want to write a client using Java Management Extensions (JMX) in Ruby to manage a remote Java application.
Use the jmx4r Ruby gem. This library significantly simplifies use of the JMX API. To install jmx4r:
jruby –S gem install jmx4r
To establish a connection with a JMX service, use the establish_connection class method:
JMX::MBean.establish_connection :host => "localhost", :port => 1099
To find an MBean by name, use the find_by_name class method:
os = JMX::MBean.find_by_name "java.lang:type=OperatingSystem"
The find_by_name method returns a dynamic object based around the MBean interface. In the case of the MBean named java.lang:type=OperatingSystem, the Java Virtual Machine exposes an MBean with several attributes about the underlying operating system. These JMX attributes can be simply accessed as properties. For example, to output the number of available processors:
p "Running with #{os.available_processors} processors."
The actual attribute name is AvailableProcessors. The jmx4r library converts this name into a more Ruby-like form.
Similarly, JMX operations are invoked as method calls. For example, to force a garbage collection:
memory = JMX::MBean.find_by_name "java.lang:type=Memory"

memory.gc
The jmx4r library also supports the ability to query for MBeans. shows this functionality in action. In this example, JMX is used to discover the available JMS queues in an Apache ActiveMQ JMS server.
Example . Querying MBeans
include Java



require 'rubygems'

gem 'jmx4r'

require 'jmx4r'



JMX::MBean.establish_connection :host => "localhost", :port => 1099



queues = JMX::MBean.find_all_by_name \

    "org.apache.activemq:BrokerName=localhost,Type=Queue,*"



queues.each do |queue|

    p "Queue #{queue.name} contains #{queue.queue_size} queued messages."

end
Depending on the available queues, the output might be similar to this:
Queue LogQueue contains 25 queued messages.

Queue OrderQueue contains 5 queued messages.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Accessing Native Libraries with JRuby
Inhaltsvorschau
You want to access native libraries such as Windows DLLs or Unix shared objects (.so) from JRuby.
Use the Java Native Access (JNA) API to access the operating system’s libraries using only Java or any other JVM-based language like JRuby. JNA uses a dynamic architecture that eliminates the chore of creating, compiling, and distributing native interface files, which was required in other Java frameworks like the Java Native Interface (JNI). shows how you can access the disk information from calls to the native Windows libraries.
Example . JNA example showing Windows disk space
include Java



import com.sun.jna.ptr.LongByReference



Kernel32 = com.sun.jna.NativeLibrary.getInstance('kernel32')

GetDiskFreeSpace =  Kernel32.getFunction('GetDiskFreeSpaceExA')

avail = LongByReference.new

total = LongByReference.new

total_free = LongByReference.new

num = GetDiskFreeSpace.invokeInt(["C:\\", avail, total, total_free].to_java)

puts "available: #{avail.value}"

puts "total: #{total.value}"

puts "total_free #{total_free.value}"
JNA is a great match with JRuby and makes it easier to create cross-platform applications that run inside the Java Virtual Machine while still accessing platform-specific APIs. The dynamic architecture is also philosophically in tune with Ruby development because it uses designs that eliminate extraneous code and facilitates rapid .
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 4: Enterprise Java
Inhaltsvorschau
As discussed in the introduction to , one of JRuby’s great strengths is its ability to seamlessly interact with the wide variety of available Java libraries. One of the areas where this is most relevant is in the so-called enterprise domain, where Java has become well entrenched. Much of Java’s success has come from the Java Enterprise Edition (Java EE, formerly known as J2EE) platform standards. But platforms that are not Java standards have been just as critical. Two will be covered in this chapter: Spring Framework and Hibernate. Regardless of whether a particular technology is a standard or not, all enterprise Java platforms are designed to enable developers to focus on developing business and presentation logic rather than infrastructure and integration.
This chapter starts with a recipe about using Java Naming and Directory Interface (JNDI) objects from Ruby. As its name implies, JNDI is an API for accessing directory services. JNDI presents application developers with a unified interface that can span various services and service types. Within a Java EE application server, JNDI is used by application code to discover resources managed by the server. These could be data sources (a subject discussed throughout ), Enterprise JavaBeans (EJBs), Java Messaging Service (JMS) objects, and a variety of other resources. Your Java EE application server documentation should provide complete details on what resources are available and how you can add additional resources to the server. JNDI can also be used to access external services. In the second and third recipes, we use JNDI to connect to a remote JMS broker using the Apache ActiveMQ server so that we can send and receive JMS messages. In a later recipe, we use JNDI to connect to a Lightweight Access Protocol (LDAP) server and use JRuby to simplify the JNDI API.
Following JMS, we will look at implementing an Enterprise JavaBean (EJB). Thanks to the support for annotation-based configuration that arrived with EJB 3, EJB development has become much simpler, yet the lack of annotation support in JRuby means that you still have to write a small amount of bridge code to implement EJBs. Although JRuby and EJB may seem like an odd match at first, the EJB model can provide some significant benefits when being used with JRuby because of the instance pooling provided by Java EE containers. These containers all perform instance pooling for EJBs and only allow one consumer per EJB instance at a time. This means that when writing an EJB, whether using Java or Ruby, you do not need to worry about concurrency: the container does it for you. Many Ruby libraries, most notably ActiveRecord and Rails, have known concurrency problems; using EJBs eliminates the need to create custom instance pools as described in and in the discussion of Rails in .
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
As discussed in the introduction to , one of JRuby’s great strengths is its ability to seamlessly interact with the wide variety of available Java libraries. One of the areas where this is most relevant is in the so-called enterprise domain, where Java has become well entrenched. Much of Java’s success has come from the Java Enterprise Edition (Java EE, formerly known as J2EE) platform standards. But platforms that are not Java standards have been just as critical. Two will be covered in this chapter: Spring Framework and Hibernate. Regardless of whether a particular technology is a standard or not, all enterprise Java platforms are designed to enable developers to focus on developing business and presentation logic rather than infrastructure and integration.
This chapter starts with a recipe about using Java Naming and Directory Interface (JNDI) objects from Ruby. As its name implies, JNDI is an API for accessing directory services. JNDI presents application developers with a unified interface that can span various services and service types. Within a Java EE application server, JNDI is used by application code to discover resources managed by the server. These could be data sources (a subject discussed throughout ), Enterprise JavaBeans (EJBs), Java Messaging Service (JMS) objects, and a variety of other resources. Your Java EE application server documentation should provide complete details on what resources are available and how you can add additional resources to the server. JNDI can also be used to access external services. In the second and third recipes, we use JNDI to connect to a remote JMS broker using the Apache ActiveMQ server so that we can send and receive JMS messages. In a later recipe, we use JNDI to connect to a Lightweight Access Protocol (LDAP) server and use JRuby to simplify the JNDI API.
Following JMS, we will look at implementing an Enterprise JavaBean (EJB). Thanks to the support for annotation-based configuration that arrived with EJB 3, EJB development has become much simpler, yet the lack of annotation support in JRuby means that you still have to write a small amount of bridge code to implement EJBs. Although JRuby and EJB may seem like an odd match at first, the EJB model can provide some significant benefits when being used with JRuby because of the instance pooling provided by Java EE containers. These containers all perform instance pooling for EJBs and only allow one consumer per EJB instance at a time. This means that when writing an EJB, whether using Java or Ruby, you do not need to worry about concurrency: the container does it for you. Many Ruby libraries, most notably ActiveRecord and Rails, have known concurrency problems; using EJBs eliminates the need to create custom instance pools as described in and in the discussion of Rails in .
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating a JNDI Context
Inhaltsvorschau
You need to create a JNDI Context object in order to connect to an LDAP server or JMS broker.
Create a Ruby hash with the properties you want to use as the environment and then pass this hash to the constructor of javax.naming.InitialContext, wrapping it in a java.util.Hashtable object. For example, the code in creates a JNDI Context using the University of Michigan’s public LDAP server.
Example . Creating a custom JNDI Context
include Java



import java.util.Hashtable

import javax.naming.InitialContext

import javax.naming.Context



env = {Context::INITIAL_CONTEXT_FACTORY => "com.sun.jndi.ldap.LdapCtxFactory",

       Context::PROVIDER_URL => "ldap://ldap.itd.umich.edu:389" }



ctx = InitialContext.new(Hashtable.new(env))
Although JRuby will coerce Ruby hashes into Java objects that implement the java.util.Map interface, InitialContext objects are configured using a Hashtable. As a result, the hash must be wrapped by a Hashtable.
The properties used to instantiate the InitialContext object can also be stored in a file called jndi.properties in the Java classpath. In the case of , the following would be the contents of jndi.properties:
java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory

java.naming.provider.url = ldap://ldap.itd.umich.edu:389
With this configuration in place, the InitialContext can be easily created using the constructor:
ctx = InitialContext.new
Regardless of how it is configured, the value of the java.naming.factory.initial property must be a class available on the classpath. As discussed in , JRuby has the ability to add JAR files to the classpath dynamically. However, that capability does not apply to classes used in this type of factory class. This is because JAR files added dynamically to the classpath by JRuby are only visible from Ruby code. Throughout the next recipe, for example, the java.naming.factory.initial property is set to org.apache.activemq.jndi.ActiveMQInitialContextFactory. If you tried to add this class (and its dependencies) to the classpath in JRuby, a
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Sending JMS Messages
Inhaltsvorschau
Your application needs to send messages to a Java Messaging Service (JMS) message broker.
Add any necessary JAR files to the classpath. Create a javax.naming.InitialContext object as described in . The environment settings will be documented by the JMS broker vendor. For example, to connect to an instance of Apache ActiveMQ, you would use these properties:
env = { Context::INITIAL_CONTEXT_FACTORY =>

        "org.apache.activemq.jndi.ActiveMQInitialContextFactory",

        Context::PROVIDER_URL =>

        "tcp://localhost:61616" }
Once the InitialContext has been properly created, look up the JMS ConnectionFac⁠t⁠o⁠r⁠y and Destination objects:
connection_factory = ctx.lookup("ConnectionFactory")

destination = ctx.lookup("dynamicQueues/output.queue")
The rest is simply JMS boilerplate, which we can encapsulate into a Ruby class as seen in .
Example . Sending a JMS message from Ruby
include Java



import java.util.Hashtable

import javax.naming.InitialContext

import javax.naming.Context

import javax.jms.Session



class JmsSender



  def initialize(environment)

     @context = InitialContext.new(Hashtable.new(environment))

     @connection_factory = @context.lookup("ConnectionFactory")

  end



  def send_text_message(destination_name, message_text)

    destination = @context.lookup(destination_name)

    connection = @connection_factory.create_connection()

    session = connection.create_session(false, Session::AUTO_ACKNOWLEDGE)

    producer = session.create_producer(destination)

    message = session.create_text_message

    message.text = message_text

    producer.send(message)

    session.close

  end

end



env = { Context::INITIAL_CONTEXT_FACTORY =>

        "org.apache.activemq.jndi.ActiveMQInitialContextFactory",

       Context::PROVIDER_URL =>

       "tcp://localhost:61616" }

sender = JmsSender.new(env)



sender.send_text_message("dynamicQueues/output.queue", "hello to JMS from Ruby")
This message can then be seen in the ActiveMQ administrative web client, as in .
As discussed in , to create a javax.naming.InitialContext object using
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Receiving JMS Messages
Inhaltsvorschau
Your application needs to receive messages from a JMS message broker.
The initial setup is similar to sending JMS messages: create a JNDI InitialContext object and look up the ConnectionFactory and destination from the JNDI context. Using the ConnectionFactory, create a Connection object and from the Connection, create a Session object. The Session object can be used to create a MessageConsumer for a . The MessageConsumer object has two methods for receiving messages, both named receive. If receive is called with no arguments, then the method blocks until a message is available. If receive is called with an argument (which must be numeric), the method blocks until a message is available or the specific number of milliseconds passes.
contains some basic code for receiving a message. Once the message is received, it is inspected to see if it is a text message and, if so, the text is output.
Example . Receiving a JMS message
include Java



import java.util.Hashtable

import javax.naming.InitialContext

import javax.naming.Context

import javax.jms.Session



env = { Context::INITIAL_CONTEXT_FACTORY =>

        "org.apache.activemq.jndi.ActiveMQInitialContextFactory",

       Context::PROVIDER_URL =>

       "tcp://localhost:61616" }



context = InitialContext.new(Hashtable.new(env))

connection_factory = context.lookup("ConnectionFactory")



destination = context.lookup("dynamicQueues/output.queue")

connection = connection_factory.create_connection()

session = connection.create_session(false, Session::AUTO_ACKNOWLEDGE)

consumer = session.create_consumer(destination)



connection.start



message = consumer.receive

if (message.respond_to? 'text')

 p "message = #{message.text}"

else

 p "message isn't a text message"

end



connection.stop

session.close
Note that in , we start the connection before receiving a message. A running connection is required before receiving messages whereas it is not for sending messages.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Implementing an Enterprise JavaBean with JRuby
Inhaltsvorschau
You want to encapsulate some Ruby code into an Enterprise JavaBean (EJB) in order to easily integrate it with other EJBs and servlets as well as take advantage of EJB services such as instance pooling, security, and transactions.
Create an interface and implementation class for your EJB. A simple EJB interface, annotated with @Local is in .
Example . EJB local interface
package org.jrubycookbook.j2ee.ejb;



import javax.ejb.Local;



@Local

public interface Reverser {

    public String reverse(String string);

}
In the implementation class, create an initialization method and use it to create an instance of the JRuby runtime. This could be done with any of the techniques discussed in . Annotate this initialization method with the @PostConstruct annotation. Then in each business method (i.e., those defined by the EJB interface), wrap the method arguments in Ruby objects, add them to the runtime, and finally execute the appropriate block of Ruby code. includes a JRuby-based EJB class. In this example, the code is inline, but it could just as easily be in an external file.
Example . JRuby EJB
package org.jrubycookbook.j2ee.ejb;



import javax.annotation.PostConstruct;

import javax.ejb.Stateless;



import org.jruby.Ruby;

import org.jruby.RubyString;

import org.jruby.javasupport.JavaEmbedUtils;



@Stateless

public class ReverserBean implements Reverser {



    private Ruby ruby;



    @PostConstruct

    public void init() {

        ruby = JavaEmbedUtils.initialize(Collections.EMPTY_LIST);

    }



    public String reverse(String string) {

        ruby.getGlobalVariables().set("$message", ruby.newString(string));

        return ruby.evalScriptlet("$message.reverse").asJavaString();

    }



}
This EJB can then be accessed by servlets and other EJBs in the same container. includes a servlet that uses this EJB.
Example . Servlet accessing the JRuby EJB
package org.jrubycookbook.j2ee.servlet;



import java.io.IOException;



import javax.ejb.EJB;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;



import org.jrubycookbook.j2ee.ejb.Reverser;



public class ReverseServlet extends HttpServlet {



    @EJB

    private Reverser reverser;



    protected void doGet(HttpServletRequest req, HttpServletResponse resp)

            throws ServletException, IOException {

        String result = reverser.reverse(req.getParameter("word"));

        resp.getWriter().println(result);

    }



}
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Defining Spring Beans in JRuby
Inhaltsvorschau
You use the Spring Framework as a Dependency Injection (DI) container and wish to define some of your beans with JRuby.
Create a Java interface that defines the methods you will be implementing in your Ruby class. Use jruby element within the lang namespace in the Spring XML configuration to define a bean using both the interface and the location of the Ruby script. JRuby beans can also be configured using the lang:property element. A simple JRuby bean definition can be seen in .
Example . Simple Spring JRuby bean definition
1 <?xml version="1.0" encoding="UTF-8"?>

2 <beans xmlns="http://www.springframework.org/schema/beans"

3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4     xmlns:lang="http://www.springframework.org/schema/lang"

5     xsi:schemaLocation="http://www.springframework.org/schema/beans

6         http://www.springframework.org/schema/beans/spring-beans.xsd

7         http://www.springframework.org/schema/lang

8         http://www.springframework.org/schema/lang/spring-lang.xsd">

9

10    <lang:jruby id="rubyListener"

11        script-interfaces="org.jrubycookbook.ch04.Listener"

12        script-source="classpath:org/jrubycookbook/ch04/ruby_listener.rb">

13        <lang:property name="prefix" value="(from Ruby) " />

14    </lang:jruby>

15

16 </beans>
In this example, lines 2 through 8 are the boilerplate Spring configuration needed to set up both the default and lang namespaces. Lines 10 through 14 contain the actual bean definition including the setting of a property named prefix. The interface is defined in and the Ruby implementation is in .
Example . Simple interface for Spring bean
package org.jrubycookbook.ch04;



public interface Listener {

    public void receiveMessage(String message);

}
Example . Ruby script referenced from Spring configuration
class RubyListener

    # setter for prefix property

    def setPrefix(p)

        @prefix = p

    end



    # implementation of Listener interface

    def receiveMessage(s)

        puts "#{@prefix}Got Message: #{s}"

    end

end



RubyListener.new
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating Refreshable JRuby Spring Beans
Inhaltsvorschau
Your Spring container includes beans that you want to reload when their underlying definitions change.
Add a refresh-check-delay attribute to the lang:jruby element in your Spring XML configuration file. The use of this attribute tells Spring to watch the resource referenced in the script-source attribute. The value indicates how many milliseconds will pass between scans of the resource for changes.
Alternatively, you can apply a default value for the refresh-check-delay attribute by using the defaults element in the lang namespace. For example, to apply a one second delay to all dynamic-language beans in the ApplicationContext, include this element in your XML configuration file:
<lang:defaults refresh-check-delay="1000"/>
One simple way to demonstrate this refreshable bean functionality is to use Spring’s support for Java Timer objects. The Spring configuration XML in the same rubyListener bean defined in and adds an implementation of java.util.TimerTask to output the current time. It also includes the Spring plumbing necessary to invoke this task every five seconds.
Example . Refreshable JRuby Spring bean called by a TimerTask
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:lang="http://www.springframework.org/schema/lang"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/lang

        http://www.springframework.org/schema/lang/spring-lang.xsd">



    <lang:defaults refresh-check-delay="1000" />



    <lang:jruby id="rubyListener"

        script-interfaces="org.jrubycookbook.ch04.Listener "

        script-source="classpath:org/jrubycookbook/ch04/ruby_listener.rb">

        <lang:property name="prefix" value="(from Timer) " />

    </lang:jruby>



    <bean id="sendDateTask" class="org.jrubycookbook.ch04.SendDateTask">

        <property name="listener" ref="rubyListener"/>

    </bean>



    <bean id="scheduledTask"

        class="org.springframework.scheduling.timer.ScheduledTimerTask">

        <property name="period" value="5000" />

        <property name="timerTask" ref="sendDateTask" />

    </bean>



    <bean id="timerFactory"

        class="org.springframework.scheduling.timer.TimerFactoryBean">

        <property name="scheduledTimerTasks">

            <list>

                <ref bean="scheduledTask" />

            </list>

        </property>

    </bean>

</beans>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Defining JRuby Spring Beans Inline
Inhaltsvorschau
You’re using Spring and want to define beans in JRuby directly inside your Spring XML configuration file instead of in an external file.
Instead of providing a resource location with a script-source attribute, you can include JRuby script inside an inline-script element in the lang namespace as seen in .
Example . JRuby script inside an inline-script element
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:lang="http://www.springframework.org/schema/lang"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/lang

        http://www.springframework.org/schema/lang/spring-lang.xsd">



    <lang:jruby id="rubyListener"

        script-interfaces="org.jrubycookbook.ch04.Listener">

        <lang:inline-script><![CDATA[

class RubyListener

    def setPrefix(p)

        @prefix = p

    end



    # implementation of Listener interface

    def receiveMessage(s)

        puts "#{@prefix}Got Message: #{s}"

    end

end



RubyListener.new

        ]]></lang:inline-script>

        <lang:property name="prefix" value="(from Ruby) " />

    </lang:jruby>



</beans>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Applying Spring-Aware Interfaces to JRuby Objects
Inhaltsvorschau
Your Spring ApplicationContext contains JRuby-based beans that need to implement one of the Aware interfaces, such as org.springframework.context.ApplicationCon⁠tex⁠tAware.
Include implementations of the methods defined in the interface in your JRuby class and add the appropriate interface name to the script-interfaces attribute.
The Spring Framework includes a number of interfaces that can be used to make a bean aware of its surroundings. Generally, these interfaces define a single method that is called by the container during initialization. Here is a sampling of these interfaces:
org.springframework.context.ApplicationContextAware
The ApplicationContext instance that contains this bean is passed to the s⁠e⁠tA⁠p⁠p⁠l⁠i⁠cationContext() method.
org.springframework.beans.factory.BeanFactoryAware
The BeanFactory instance that contains this bean is passed to the setBeanF⁠a⁠c⁠t⁠o⁠r⁠y() method.
org.springframework.beans.factory.BeanNameAware
The name of this bean in the containing BeanFactory is passed to the setBeanName() method.
org.springframework.context.ResourceLoaderAware
A ResourceLoader, which can resolve a String identifier to a Resource object, is passed to the setResourceLoader() method.
org.springframework.context.MessageSourceAware
A MessageSource, which can resolve a message code and parameters to an appropriately internationalized message, is passed to the setMessageSource() method.
org.springframework.web.context.ServletContextAware
A javax.servlet.ServletContext object is passed to the setServletContext() method.
shows an inline implementation of the BeanNameAware interface.
Example . Inline JRuby Spring bean that implements the BeanNameAware interface
<lang:jruby id="rubyListener"

    script-interfaces="org.jrubycookbook.ch04.Listener,

               org.springframework.beans.factory.BeanNameAware">

    <lang:inline-script><![CDATA[

class RubyListener

    # implementation of BeanNameAware interface

    def setBeanName(beanName)

        @beanName = beanName

    end



    # implementation of Listener interface

    def receiveMessage(s)

        puts "Hello, I'm named #{@beanName}"

        puts "#{@prefix}Got Message: #{s}"

    end

end



RubyListener.new

    ]]></lang:inline-script>

</lang:jruby>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating Spring MVC Controllers with JRuby
Inhaltsvorschau
Redeploying a Java controller in Spring MVC can be time-consuming and disruptive to development. This is especially the case for web applications with many modules and/or large amounts of data loaded on startup. You would like to modify your controller code without reloading the running web application.
Spring’s dynamic language support can speed up the development of Spring MVC by allowing you to define the controllers as JRuby objects. Not only can you eliminate the compilation step needed for Java development, but with Spring’s bean feature (see ), controller classes can be updated and redefined at runtime without a redeployment of the full web application. Open the Spring configuration file and create a JRuby controller by defining a Spring bean using the dynamic language elements as described in and . Set the value of script-interfaces to org.springframework.web.servlet.mvc.Controller and script-source to the location of a Ruby file that will define and instantiate the controller class. Note that the scripts-source value is relative to the web application folder. shows a Spring configuration file with a JRuby controller named hellocontroller that renders a JSP page.
Example . Spring configuration file with simple JRuby controller
<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:lang="http://www.springframework.org/schema/lang"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/lang

http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">



  <lang:jruby id="hellocontroller" refresh-check-delay="3000"

    script-source="/WEB-INF/ruby/hello.rb"

    script-interfaces="org.springframework.web.servlet.mvc.Controller">

  </lang:jruby>



  <bean id="viewResolver"

    class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="viewClass"

      value="org.springframework.web.servlet.view.JstlView"/>

    <property name="prefix" value="/WEB-INF/jsp/"/>

    <property name="suffix" value=".jsp"/>

  </bean>



  <bean id="urlMapping"

    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

    <property name="mappings">

      <props>

        <prop key="/hello.htm">hellocontroller</prop>

      </props>

    </property>

  </bean>

</beans>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using Hibernate with JRuby
Inhaltsvorschau
You would like to use Hibernate in your JRuby application.
Ideally, working with a Hibernate Data Access Object (DAO) should be no different from any other Java class. The main concern for JRuby developers is the use of Java Generics and JRuby’s inability to create classes or call methods with input arguments that use the Generics feature. Hibernate gives Java developers a lot of flexibility in the implementation of the DAO and many leverage Java Generics to reduce the size of classes and method counts. However, the typical pattern for creating DAOs in the most popular online tutorials do not expose the Generics as part of the DAOs’ public API, even though they are used internally. They are commonly created through a factory interface or by instantiating wrapper DAOs for classes. The JRuby program in accesses the PersonDao through a factory while the EventDao is directly .
Example . Accessing Hibernate Data Access Objects
include Java



import example.dao.PersonDao

import example.dao.DaoFactory

import example.dao.EventDao

import example.model.Person

import example.model.Event

import util.HibernateUtil



event_dao = EventDao.new

event_dao.set_session HibernateUtil::get_session_factory.get_current_session

dao.create(Event.new("JRuby Meeting",java.util.Date.new))

dao.find_all.each do |e| puts "#{e.get_title } #{e.get_date}"; end



person_dao = DaoFactory.instantiate(PersonDao.class)

dao.create(Person.new("Justin","Wood"))

dao.create(Person.new("Brian","Henry"))

dao.find_all.each do |p| puts "#{p.get_firstname} #{p.get_lastname}"; end
The Hibernate session is obtained through a static method in the HibernateUtil class and manually injected into the EventDao class. It’s a common Hibernate design pattern to provide access to the Hibernate session factory through a static method in a global utility class. The HibernateUtil class becomes the common point of configuration and management and can hide many of the mapping details from your DAOs.
Database transactions can be nicely expressed using a Ruby function that yields to an inputted block. The block contains the database interaction code and is evaluated the enclosing parent function’s call to initialize and end the transaction. Errors can be detected and handled in the transaction function and kept out of the business code. The result is clean API that eliminates the verbose and repetitive transaction calls and an enhanced clarity of the transactional code, which is now identified through a function metaphor rather than explicit API calls to begin and end the transaction. defines a
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the Java Persistence API with JRuby
Inhaltsvorschau
You want to use the Java Persistence API (JPA) in your JRuby application.
Use the static JPA method Persistence.createEntityManagerFactory() to generate a factory for your persistence unit. A call to the factory’s createEntityManager() method generates a new EntityManager class, which is your primary tool for accessing the Persistence API. The EntityManager is analogous to Hibernate’s Session or Toplink’s ClientSession object and contains the methods to interact with the database and your model objects. The EntityManager object is not threadsafe and shouldn’t be used with multiple concurrent requests. It is designed to be used and discarded in a relatively short amount of time and not as a long-running software component. shows a JRuby application that creates a few User objects and then queries the database to confirm that they were successfully added.
Example . Example JPA access from JRuby
include Java



import javax.persistence.Persistence

import cookbook.User



def with_trans(em)

 t = em.getTransaction();

 begin

   t.begin()

   yield

   t.commit

 ensure

   t.rollback if t.isActive

 end

end



emf = Persistence.createEntityManagerFactory("hello-world")

em = emf.createEntityManager



with_trans(em) do

      u = User.new("stephen","lee","slee","password","stephen@ora.com")

      u2 = User.new("stephen","smith","ssmith","password","ssmith@ora.com")

      em.persist(u)

      em.persist(u2)

end

query = em.createQuery("select u from User u where u.firstname = :firstname").

query.set_parameter("firstname", "stephen").

hu = query.get_result_list



hu.each do |u|

  puts "found #{u.firstname} #{u.lastname}"

end



em.close

emf.close
The example demonstrates the use of a block once again (see ) to express a JPA transaction. This helper method also automatically rolls back the transaction if the commit should fail.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Making SOAP Calls
Inhaltsvorschau
Credit: Steven Shingler
You need to invoke a remote method through a SOAP-based web service.
Use the Mule client module, available from http://mule.mulesource.org, and a Ruby XML parsing library such as REXML or Hpricot. uses Mule to make a request to one of the web services provided by the National Oceanic and Atmospheric Administration (NOAA).
Example . Making a SOAP request with the Mule client module
include Java



require "rexml/document"

import org.mule.module.client.MuleClient



url = "axis:http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php"

method = "method=LatLonListZipCode"

client = MuleClient.new

message = client.send("#{url}?#{method}", "10036", nil)

doc = REXML::Document.new message.payload

puts doc.root.elements[1].text

exit
To run this script, Mule and several dependencies need to be added to the classpath. Because of classloader requirements, these dependencies must be on the system classpath (e.g., through the use of the CLASSPATH environment variable); they cannot be added to the classpath by using JRuby’s extension of the require method as described in . For this particular script, the dependencies can be added to the classpath using these commands:
export MULE_LIB=/opt/mule/lib

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/activation-1.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/axis-1.4.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/axis-jaxrpc-1.4.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/backport-util-concurrent-3.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-beanutils-1.7.0.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-codec-1.3.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-collections-3.2.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-discovery-0.2.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-httpclient-3.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-io-1.3.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-lang-2.3.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-logging-1.1.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-pool-1.4.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/dom4j-1.6.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/geronimo-j2ee-connector_1.5_spec-1.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/geronimo-servlet_2.5_spec-1.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/jaxen-1.1.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/jug-2.0.0-asl.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-core-2.0.2.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-module-client-2.0.2.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-transport-axis-2.0.2.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/saaj-api-1.3.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/stax-api-1.0.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/wsdl4j-1.6.1.jar

export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/wstx-asl-3.2.6.jar
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Simplifying LDAP Access
Inhaltsvorschau
You are looking up entries and attributes in an LDAP directory through JNDI and are looking to simplify the API.
Use JRuby’s open class feature (described in ) to add helper methods to the com.sun.jndi.ldap.LdapCtx class.
Although powerful, the JNDI API can frequently feel unnecessarily verbose. For example, the Java code required to access a single attribute value is awkward:
// Lookup the entry

LdapContext entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu");

// First, get all of the Attributes associated with this entry.

Attributes attributes = entry.getAttributes("");

// Then get a single named Attribute.

Attribute attribute = attributes.get("mail");

// Then actually get the value.

String value = (String) attribute.get();
For an attribute with multiple values, it’s even worse:
// Lookup the entry

LdapContext entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu");

// First, get all of the Attributes associated with this entry.

Attributes attributes = entry.getAttributes("");

// Then get a single named Attribute.

Attribute attribute = attributes.get("mail");

// Then get a NamingEnumeration of the attribute values.

NamingEnumeration ne = attribute.getAll();

// Create a list, loop through the NamingEnumeration,

// and add each value to the list

List<String> values = new ArrayList<String>();

while (ne.hasMore()) {

    values.add(ne.next());

}
shows two methods being added to the LdapCtx class, which simplify this API significantly.
Example . Adding methods to the LdapCtx class
include Java



import com.sun.jndi.ldap.LdapCtx



class LdapCtx

    def get_attribute_value(key)

        get_attributes("", [key].to_java(:string)).get(key).get

    end

    def get_attribute_values(key)

        values = []

        enum = get_attributes("", [key].to_java(:string)).get(key).get_all

        while enum.has_more

            values << enum.next

        end

        return values

    end

end
Adding these methods makes the following code to access the LDAP attributes:
entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu")



p "Email = #{entry.get_attribute_value("mail")}"

entry.get_attribute_values("cn").each do |name|

    p "Name = #{name}"

end
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 5: User Interface and Graphics
Inhaltsvorschau
The JRuby community has paid a lot of attention to web development, but JRuby is also a powerful tool for client application development. By allowing the runtime to access the graphics subsystem, JRuby can be used to create GUI applications with the Abstract Windowing Toolkit (AWT), Swing and the Simple Widget Toolkit (SWT), as well as newer projects like Qt Jambi. These toolkits have a rich set of UI widgets but they also permit tight integration with the native operating system. A few recipes in this chapter explain how to use JRuby to create system tray and desktop components and access native GUI libraries.
Given the popularity of declarative programming and Ruby’s powerful Language (DSL) building capabilities, it is to be expected that JRuby developers would explore ways to improve traditional Java UI programming. There are several options to facilitate Swing development: Swigby, Cheri::Swing, Monkeybars, and . Similarly, the Glimmer Eclipse project was created for SWT and QT::JRuby has built-in DSL support.
The Rawr gem is a useful tool for packaging your JRuby applications desktop as well as the Web. This gem provides a set of Rake tasks that can be configured to package your JRuby programs as executable JAR files, Windows executables, Mac OS X applications, and Web Start applications. A recipe also describes techniques for using JRuby to build Java applets.
Image processing is one of the few areas where Ruby runtimes still depend on native or C code. Use RMagic4J and ImageVoodoo as alternatives to the popular RMagic and ImageScience gems. You can also access the Java 2D API for advanced processing needs.
You want to build your Java Swing user interface with JRuby.
JRuby’s runtime support extends to the graphics libraries and Swing components. shows a simple Swing application that displays a message in a window.
Example . Simple Swing UI
include Java

import javax.swing.JFrame



frame = JFrame.new "JRuby Message"

frame.default_close_operation = JFrame::EXIT_ON_CLOSE

msg = javax.swing.JLabel.new "JRuby Rocks"

frame.content_pane.add msg

frame.pack

frame.visible = true
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
The JRuby community has paid a lot of attention to web development, but JRuby is also a powerful tool for client application development. By allowing the runtime to access the graphics subsystem, JRuby can be used to create GUI applications with the Abstract Windowing Toolkit (AWT), Swing and the Simple Widget Toolkit (SWT), as well as newer projects like Qt Jambi. These toolkits have a rich set of UI widgets but they also permit tight integration with the native operating system. A few recipes in this chapter explain how to use JRuby to create system tray and desktop components and access native GUI libraries.
Given the popularity of declarative programming and Ruby’s powerful Language (DSL) building capabilities, it is to be expected that JRuby developers would explore ways to improve traditional Java UI programming. There are several options to facilitate Swing development: Swigby, Cheri::Swing, Monkeybars, and . Similarly, the Glimmer Eclipse project was created for SWT and QT::JRuby has built-in DSL support.
The Rawr gem is a useful tool for packaging your JRuby applications desktop as well as the Web. This gem provides a set of Rake tasks that can be configured to package your JRuby programs as executable JAR files, Windows executables, Mac OS X applications, and Web Start applications. A recipe also describes techniques for using JRuby to build Java applets.
Image processing is one of the few areas where Ruby runtimes still depend on native or C code. Use RMagic4J and ImageVoodoo as alternatives to the popular RMagic and ImageScience gems. You can also access the Java 2D API for advanced processing needs.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating Swing Applications
Inhaltsvorschau
You want to build your Java Swing user interface with JRuby.
JRuby’s runtime support extends to the graphics libraries and Swing components. shows a simple Swing application that displays a message in a window.
Example . Simple Swing UI
include Java

import javax.swing.JFrame



frame = JFrame.new "JRuby Message"

frame.default_close_operation = JFrame::EXIT_ON_CLOSE

msg = javax.swing.JLabel.new "JRuby Rocks"

frame.content_pane.add msg

frame.pack

frame.visible = true
JRuby can access the entire Swing API, including advanced features like the Look and Feel libraries. shows how to toggle between Swing’s default Metal theme and the native platform’s Look and Feel.
Example . Changing the application’s look and feel
include Java



import javax.swing.JFrame

import javax.swing.UIManager



frame = JFrame.new "JRuby Look And Feel"

frame.default_close_operation = JFrame::EXIT_ON_CLOSE

frame.content_pane.layout = java.awt.GridLayout.new(1, 2)



{:metal => "javax.swing.plaf.metal.MetalLookAndFeel",

 :system => UIManager::getSystemLookAndFeelClassName}.each do |l,c|

 but = javax.swing.JButton.new l.to_s

 but.add_action_listener do |evt|

    UIManager::look_and_feel = c

    javax.swing.SwingUtilities::updateComponentTreeUI frame

    frame.pack

 end

 frame.add(but)

end



frame.pack

frame.visible = true
You can access third-party Look and Feel libraries such as Substance or Napkin by including their JAR files in the Java classpath and referencing the name of the Look and Feel class.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Swing Event Handling
Inhaltsvorschau
You want to handle events that are generated by Swing components.
You generally want to use the block coercion feature in JRuby for most GUI event processing. Event listeners that define only a single method such as javax.awt.event.ActionListener can make use of this feature and allow for very concise event-handling code. The application in uses blocks to capture the button click event and changes to the text field.
Example . Events handled through block coercion
include Java

import javax.swing.JFrame



frame = JFrame.new "Event Handler - Coerced"

frame.default_close_operation = JFrame::EXIT_ON_CLOSE



t = javax.swing.JTextField.new(10)

b = javax.swing.JButton.new("search")

b.add_action_listener { |evt| puts "searching" };

t.document.add_document_listener { |evt| puts "checking #{t.text}" };



frame.layout = java.awt.GridLayout.new(1, 2)

frame.add t

frame.add b

frame.pack

frame.visible = true
You can also instantiate the listener’s Java interface using the impl method, passing a block inside which the event is handled. This approach is useful when the event handler interface contains multiple methods. shows how to intercept events from the menu component.
Example . Events handled through an instance of a Java interface
include Java

import javax.swing.JFrame



frame = JFrame.new

frame.default_close_operation = JFrame::EXIT_ON_CLOSE



bar = javax.swing.JMenuBar.new

menu = javax.swing.JMenu.new "File"

item = javax.swing.JMenuItem.new "Open"



menu.add_menu_listener(javax.swing.event.MenuListener.impl do |method, evt|

  puts evt.class

  case method.to_s

    when "menuDeselected"

        puts 'hidden'

    when "menuSelected"

        puts 'visible'

  end

end)



menu.add item

bar.add menu

frame.jmenu_bar = bar

frame.pack

frame.visible = true
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Long-Running Tasks in Swing Applications
Inhaltsvorschau
The Swing event dispatching thread is responsible for drawing the user interface and event handling. You want to execute a long-running task that is initiated from a Swing event but allow the interface to remain responsive and active.
The class javax.swing.SwingWorker is designed to run long-running jobs while allowing for safe UI updates within the event dispatch thread. The implementation has evolved over the years through several open source projects and publications and was formally added to the core Java library in Java 6. To use SwingWorker, you first create a new class that extends SwingWorker. Next, implement the required doInBackground method with your long-running action. shows SwingWorker in action. Note that the button component is a member of the worker class because the variable is not accessible within the scope of the new class.
Example . Using the SwingWorker for long-running jobs
include Java

import javax.swing.JFrame



frame = JFrame.new "Swing Worker"

frame.default_close_operation = JFrame::EXIT_ON_CLOSE



start = javax.swing.JButton.new("start")



#define the function using a block

start.add_action_listener do |evt|

  class MySwingWorker < javax.swing.SwingWorker

    attr_accessor :button

    def doInBackground

      10.times do

        puts "thread #{self.hashCode} working"

        sleep(1)

      end

      self.button.text = "Completed"

    end

  end



  sw = MySwingWorker.new

  sw.button = start

  sw.execute

end



frame.add start

frame.pack

frame.visible = true
As of version 1.1, JRuby cannot instantiate abstract Java classes, so you must subclass SwingWorker to provide the implementation of the abstract methods. This is one of the few areas were JRuby results in less fluid and elegant code than its Java counterpart, but the JRuby team is working on improving support for abstract classes in future versions of JRuby.
SwingWorker has optional methods that provide advanced features, such as incremental job progress, job cancellation, and completion detection. Explore the API and overload the optional methods in your Ruby class to use these features.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Packaging Standalone Applications
Inhaltsvorschau
You want to package your JRuby application as an executable JAR file, Windows , or Mac OS X application.
Install the Rawr gem. This gem was created by David Koontz to simplify the packaging of JRuby applications for Windows, Mac, Linux, and Java environments:
$ jruby –S gem install rawr
Set up the Rawr build environment by running the rawr install command in your build folder, usually the top level of your project folder:
$ cd /projects/rawrdemo

$ jruby –S rawr install
This command creates two files: build_configuration.yaml and src/org/rubyforge/rawr/Main.java, a Java class that instantiates a JRuby runtime and executes your Ruby application’s script. Copy your JRuby application’s files into the newly created src folder. If your project depends upon custom Java classes, package those class files into a JAR file and place your project JAR file along with any JAR files upon which your application depends in the lib/java folder. You must also have the jruby-complete.jar file in the lib/java folder.
Open the build_configuration.yaml file and set the project_name parameter to the name you would like for the final executable. Change the main_ruby_file parameter to the application’s main execution script name or rename the file to the default script name, main.rb. shows a sample configuration file.
Example . Example Rawr configuration file
# Name of the created jar file

project_name: jruby_cookbook_app



# Ruby file to invoke when jar is started

main_ruby_file: jruby_cookbook_main

Executable JAR

Run the rawr:jar Rake task to generate an executable JAR file:
$ jruby –S rake rawr:jar
The resulting files can found in the package/deploy directory. This includes the main executable JAR file jruby_cookbook_app.jar, a configuration file, and the JRuby runtime JAR file. You will need to include all the files in the folder along with the JAR files when you distribute your application. To test the JAR file, run:
$ java –jar package/deploy/jruby_cookbook_app.jar
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Packaging JRuby Web Start Applications
Inhaltsvorschau
You want to package your JRuby program as a Java Web Start application.
Install the Rawr gem. See for instructions on how to use and configure the gem. Because of the Web Start security model and JRuby’s use of the VM, the main JAR file and the JRuby runtime JAR file must be signed to run in the Web Start security sandbox. Start by generating a keystore file named myKeystore with the alias myself. Enter a password and other information when prompted:
$ keytool -genkey -keystore myKeystore -alias myself

Enter keystore password:  dumbpassword

What is your first and last name?

  [Unknown]:  Henry Liu

What is the name of your organizational unit?

  [Unknown]:  Global Digital

What is the name of your organization?

  [Unknown]:  MTV Networks

What is the name of your City or Locality?

  [Unknown]:  New York

What is the name of your State or Province?

  [Unknown]:  NY

What is the two-letter country code for this unit?

  [Unknown]:  US

Is CN=Henry Liu, OU=Global Digital, O=MTV Networks, L=New York, ST=NY, C=US

correct?

  [no]:  yes



Enter key password for <myself>

        (RETURN if same as keystore password):
Using your newly created keystore, create a self-signed certificate with the selfcert option:
$ keytool -selfcert -alias myself -keystore myKeystore
Edit the build_configuration.yaml file and create a hash named web_start containing the key self_sign with the value true and a self_sign_passphrase key whose value is set to the certificate’s password. Create a hash named jnlp with the required values for codebase, description, vendor, and homepage_href. shows how to define YAML hashes in your configuration file.
Example . Web Start parameters in Rawr configuration file
web_start: { self_sign: true, self_sign_passphrase: password }



jnlp: {

    codebase: http://localhost:8080,

    description: My Webstart Demo,

    vendor: Your Name,

    homepage_href: http://www.ora.com

       }
Sign the JRuby runtime JAR file and other included JAR files that access the native system, use network services, or produce security errors:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating JRuby Applets
Inhaltsvorschau
You want to create a Java applet using JRuby.
Working with an applet in JRuby is slightly different from creating a desktop application because the Ruby code cannot instantiate its own main application window but must add components to the parent applet’s content pane. One possible solution, shown in , is to expose the content pane as a global variable to the JRuby runtime.
Example . JRuby applet with content pane in a global variable
JRubyApplet.java



package org.jrubycookbook;



import java.util.ArrayList;

import org.jruby.Ruby;

import org.jruby.javasupport.*;

import java.awt.Container;

import org.jruby.runtime.builtin.IRubyObject;

import org.jruby.runtime.*;



public class JrubyApplet extends javax.swing.JApplet {

    public void init(){

        Ruby runtime = JavaEmbedUtils.initialize(new ArrayList<String>());

        runtime.evalScriptlet("require \"java\"\nclass FreshForJava\nend\n");

        final IRubyObject blankRuby = runtime.evalScriptlet("FreshForJava.new");

        IRubyObject globValue = JavaUtil.convertJavaToRuby(runtime,

            this.getContentPane());

        globValue = Java.java_to_ruby(blankRuby, globValue, Block.NULL_BLOCK);

        GlobalVariable gv = new GlobalVariable(runtime, "$content_pane",

            globValue);

        runtime.defineVariable(gv);

        String bootRuby = "require 'appletmain' \n";

        runtime.evalScriptlet( bootRuby );

     }

}



appletmain.rb



include Java



import javax.swing.JPanel

import javax.swing.JButton



jp = JPanel.new

but = JButton.new("OK")

but.add_action_listener do |evt|

     puts "pressed"

end

jp.add(but)

$content_pane.add(jp)
Package the Ruby scripts with your Java classes into a JAR file and then reference that JAR file from inside an HTML applet tag. Include the jruby-complete.jar with the JRuby runtime along with your application JAR file through the archive parameter. shows a sample applet tag to be used in an HTML page.
Example . Applet tag for a JRuby applet
<applet width="200" height="200" align="baseline"

    code="org.jrubycookbook.JrubyApplet.class"

    codebase="." pluginspage="http://java.sun.com/j2se/1.6.0/download.html"

        archive="jrubyapplet.jar,jruby-complete.jar">

</applet>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Manipulating Images
Inhaltsvorschau
You want to resize or otherwise modify an image using JRuby.
Use a JRuby-compatible image library such as RMagick4J or ImageVoodoo for simple tasks like thumbnail generation. The Java 2D API can be used when you need more advanced image-processing capabilities.

RMagick4J

RMagick is a gem frequently used by Ruby developers for thumbnail generation or image editing but it requires the C-based ImageMagick libraries. RMagick4J was created so JRuby developers could work with the familiar API and allow their existing application to remain compatible RMagic applications. Start by installing the gem:
$ jruby -S gem install rmagick4j
demonstrates a simple thumbnail-creation operation. It also shows how to make the library compatible with the RMagick gem by using a small amount of platform-detection code to load the correct gem before including the appropriate gem.
Example . Creating thumbnails with RMagick4J
require 'rubygems'

gem defined?(JRUBY_VERSION) ? 'rmagick4j' : 'rmagick'

require 'RMagick'

include Magick



img = Image.new "avatar.jpg"

thumb = img.resize(0.25)

thumb.write "avatar-thumb.jpg"
RMagick4J has implemented most, but not all, of the functions from the original gem. The team has stated though they have a goal to provide complete compatibility with the C-based RMagick gem in the future.

ImageVoodoo

ImageVoodoo was created by JRuby core team members Tom Enebo and Nick Sieger. Its original purpose was to be an API-compatible JRuby implementation of Ryan ImageScience library, another widely used Ruby library for image processing. by installing the ImageVoodoo gem:
$ jruby -S gem install image_voodoo
shows how to create a thumbnail image using the library.
Example . Creating thumbnails with ImageVoodoo
require 'image_voodoo'



ImageVoodoo.with_image('logo-240-480.jpg') do |img|

  img.thumbnail(240) do |img|

    img.save "logo-120-240.jpg"

  end

end
The ImageVoodoo gem includes the image_science.rb file to provide compatibility with existing ImageScience code. If you open the file, you’ll see that
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating SWT Applications
Inhaltsvorschau
You want to create SWT applications using JRuby. The Standard Widget Toolkit (SWT) is probably the most popular Java client technology after the AWT and Swing libraries. It is open source software and is best known as the user interface framework used throughout the Eclipse IDE.
Download the SWT library and include the swt.jar in your classpath or use the require method to load the JAR file from your Ruby application. JRuby integrates nicely with the org.eclipse.swt.Shell and org.eclipse.swf.widgets.Display classes and is able to access all the UI widgets in the library. The code in demonstrates how to handle button events in an SWT application.
Example . Simple JRuby SWT application
include Java

require 'swt'



import org.eclipse.swt.SWT

import org.eclipse.swt.layout.RowLayout

import org.eclipse.swt.widgets.Listener



d = org.eclipse.swt.widgets.Display.new

s = org.eclipse.swt.widgets.Shell.new(d)

but =  org.eclipse.swt.widgets.Button.new(s, SWT::PUSH)

but.text = "Search"

l = org.eclipse.swt.widgets.Label.new(s,SWT::NONE)

l.text = "Click to Search"

l.set_size(100,75)



but.addListener(SWT::Selection, Listener.impl do |method, evt|

      l.text = 'searching...'

end)



s.layout = RowLayout.new

s.set_size(300,200)

s.open



while(!s.is_disposed) do d.sleep if(!d.read_and_dispatch) end

d.dispose
The Glimmer project is a JRuby DSL for creating SWT applications using a declarative syntax. It was created by Andy Maleh and is an official Eclipse project. Install the Glimmer gem with this command:
$ jruby –S gem install glimmer
The gem provides a custom DSL for composing SWT applications. It has a declarative style, using keywords and accompanying blocks to define containers as well as individual components. The widget’s models and event handlers can be associated to Ruby methods for custom event processing and state changes. You can see an example of the Glimmer DSL in .
Example . Writing an SWT application with Glimmer
include Java

require File.dirname(__FILE__) + "/../src/swt"



include Glimmer

import 'org.eclipse.swt.layout.GridLayout'



def user_name

    "default text"

end



def enabled

    true

end



@shell = shell {

  text "SWT"

  composite {

    layout GridLayout.new(2, false) #two columns with differing widths

    label { text "Hello World!"}

    text {

          text bind(self, :user_name)

          enabled bind(self, :enabled)

         }

    }

}

@shell.open
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Accessing the Native Desktop
Inhaltsvorschau
You want to create or communicate with a native application.
You can access a limited set of commonly used features in the native desktop through the java.awt.Desktop class introduced in Java 6. The Desktop class does not provide access to the entire desktop, but does allow you to perform common desktop activities such as opening the default browser, launching the default mail client, as well as printing or opening a file with its default application ().
Example . Java Desktop API
include Java

import java.awt.Desktop

import java.net.URI

import java.io.File



d = Desktop::desktop



# Open the browser

d.browse(URI.new("http://www.ora.com/")) if d.isSupported(Desktop::Action::BROWSE)



# Open your mail client and compose a message

d.mail(URI.new("mailto:jruby@ora.com")) if d.isSupported(Desktop::Action::MAIL)



# Launch the default jpg viewing application

d.open(File.new("conference_pic_1.jpg")) if d.isSupported(Desktop::Action::OPEN)



# Print a document

d.print(File.new("directions.twxt")) if d.isSupported(Desktop::Action::PRINT)
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Accessing the System Tray
Inhaltsvorschau
You want to use JRuby to create an application that runs in the Mac OS X, Windows, or KDE system tray.

Swing

You can access the Windows or Linux system tray through the Java java.awt.SystemTray class, added in Java 6, as in .
Example . A Java system tray application
include Java



import java.awt.TrayIcon

import java.awt.event.MouseListener



if (java.awt.SystemTray::isSupported())



   tray = java.awt.SystemTray::system_tray

   image = java.awt.Toolkit::default_toolkit.get_image("tray.gif")



   popup = java.awt.PopupMenu.new

   exititem = java.awt.MenuItem.new("Exit")

   exititem.addActionListener {java.lang.System::exit(0)}



   oraitem = java.awt.MenuItem.new("Go To ORA")

   oraitem.addActionListener do

    java.awt.Desktop::desktop.browse(java.net.URI.new("http://www.ora.com"))

   end



   popup.add(exititem)

   popup.add(oraitem)

   trayIcon = TrayIcon.new(image, "Tray Demo", popup)

   trayIcon.image_auto_size = true



   trayIcon.addActionListener do |evt|

    trayIcon.displayMessage("Action","Tray Action!", \

      TrayIcon::MessageType::WARNING)

   end



   trayIcon.addMouseListener(MouseListener.impl do |method, evt|

       puts "mouse event #{method.to_s}"

   end



   tray.add(trayIcon)

end

SWT

The SWT library also includes a class for accessing the system tray: org.eclipse.swt.widgets.Tray (). This SWT widget has the advantage of being available on the Windows, Linux, and Mac platforms. The OS X implementation places an icon in the desktop’s status area.
Example . SWT system tray application
include Java

require 'swt-debug'



import org.eclipse.swt.SWT

import org.eclipse.swt.widgets.Listener

import org.eclipse.swt.widgets.MenuItem



d = org.eclipse.swt.widgets.Display.new

s = org.eclipse.swt.widgets.Shell.new(d)

image = org.eclipse.swt.graphics.Image.new(d, "tray.gif")

tray = d.system_tray

item = org.eclipse.swt.widgets.TrayItem.new(tray, SWT::NONE)

item.tool_tip_text = "SWT TrayItem"



item.addListener(SWT::DefaultSelection, Listener.impl do |evt|

      puts("default selection")

end)



menu = org.eclipse.swt.widgets.Menu.new(s, SWT::POP_UP)

menuitem = MenuItem.new(menu, SWT::PUSH)

menuitem.text = "Exit"



menuitem.addListener(SWT::Selection, Listener.impl do |method, evt|

      s.close

end)



item.addListener(SWT::MenuDetect, Listener.impl do |method, evt|

      menu.visible = true

end)



item.image = image

# exclude these parameters to hide the main window

#s.setBounds(10, 10, 100,100)

#s.open()

while(!s.is_disposed) do d.sleep if(!d.read_and_dispatch) end

image.dispose

d.dispose
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Swing Development with JRuby Domain-Specific Languages
Inhaltsvorschau
The trend toward declarative GUI design can be seen in the growth of web applications and the transition of established technologies to declarative models such as Adobe Flex and JavaFX Script. You want to use a JRuby-based DSL to develop your Swing .
There are a several different projects that present DSLs for creating Swing user .

Swiby

The Swiby project is a JRuby adaptation of the declarative GUI building portion of the JavaFX Script language. Install the Swiby gem:
$ jruby –S gem install swiby
Swiby’s syntax and design is inspired from JavaFX Script, in which blocks are used to represent hierarchies of user interface containers and components. Properties are defined by single-line name-value declarations. The Swing and AWT class names are mapped to shorter, more concise names used in the DSL. Swiby eliminates some of JavaFX Script’s capitalization when defining widgets and trailing colons after property declarations. shows Swiby in action.
Example . Simple Swiby application
require 'rubygems'

require 'swiby'

require 'swiby/form'



class LabelModel

  attr_accessor :text

end

model = LabelModel.new

model.text = "Click to Search"



f = frame {

  title "Swiby Example"

  width 300

  height 100



  content {

  panel :layout => :flow do

    button("Search") { model.text="Searching...."}

    label {label bind(model, :text)}

  end

  }

}

f.visible = true
The Swiby project has some features that aren’t found in JavaFX Script, like the ability to define your styles in an external file. The styles can be loaded and applied with the simple use_styles declaration. shows how to alter the font by creating and loading a file named styles.rb.
Example . Defining Swiby styles
swibyapp.rb



frame {

  title "Swiby Example"

  width 300

  height 74

  use_styles "styles.rb"

  .

  .



styles.rb



create_styles {

  label(

    :font_family => Styles::VERDANA,

    :font_style => :italic,

    :font_size => 14,

    :color => 0xAA0000

  )

}
The gem also provides a useful form-building DSL. This is geared toward forms with simpler, grid-based layouts.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the Monkeybars Framework for Swing Development
Inhaltsvorschau
You want to develop a Swing application while following the model-view-controller (MVC) pattern.
Use Monkeybars, a library created by David Koontz, the author of Rawr. It uses the MVC design pattern, similar to web frameworks like Rails or Struts, to create JRuby client applications. Start by installing the Monkeybars gem:
$ jruby –S gem install monkeybars
The gem will add the Monkeybars tool to your JRuby execution path. This is similar to the rails command used by Ruby on Rails developers. Running monkeybars creates the main project folder and the project skeleton:
$ jruby –S monkeybars search_demo
includes a Java class that we will use with Monkeybars. This class extends JFrame and contains a button with some accompanying text. The file should be located in the src.
Example . Java GUI class for use with Monkeybars
import javax.swing.*;



public class SearchDemoJava extends JFrame {

    private JLabel message = new JLabel("Click to search");

    private JButton search = new JButton("Search");



    public SearchDemoJava(){

        this.setLayout(new java.awt.FlowLayout());

        this.setSize(300,100);

        add(search);

        add(message);

    }

}
The event-handling code and model data is defined in Ruby code. The generate Rake task, which was added along with the Monkeybars JAR file and several Ruby classes when the project was generated, is used to create the new model, view, and controller classes. Use the ALL parameter to create all these at once:
$ cd search_demo

$ jruby –S rake generate ALL="src/search"

(in C:/projects/search_demo)

Generating controller SearchController in file search_controller.rb

Generating model SearchModel in file search_model.rb

Generating view SearchView in file search_view.rb
The model class uses an instance variable to store messages that are displayed in the text label (). The variable is later mapped to a GUI component in the complementing view file.
Example . Monkeybars model file
class SearchModel

      attr_accessor :search_message

      def initialize

            @search_message = "Starting"

      end

end
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating Qt Applications with JRuby
Inhaltsvorschau
You would like to use JRuby to build applications using the Qt GUI framework. Qt is a popular cross-platform application framework for creating user interfaces. It has a rich set of components such as the Web Browser and System Tray widgets.
The Qt Jambi project lets developers leverage the Qt framework through Java. Qt Jambi is available for download from http://trolltech.com/downloads/. Download the bundle and add the files qtjambi-version.jar and qtjambi-platform-version.jar to your classpath.
Qt::JRuby is a library that brings several nice integration features when working directly with the Qt Jambi library from JRuby including a DSL for Qt. To use Qt::JRuby, you need to build the library from source. First, get the latest version of Qt::JRuby from its Git repository. Then, use Rake to build qtjruby-core.jar and install the wrapper :
$ git clone git://github.com/nmerouze/qtjruby.git

Initialize qtjruby/.git

Initialized empty Git repository in /home/henry/qtjruby/.git/

remote: Counting objects: 391, done.

remote: Compressing objects: 100% (182/182), done.

Receiving objects: 100% (391/391), 59.30 KiB | 78 KiB/s, done.

Resolving deltas: 100% (180/180), done.

$ cd qtjruby/qtjruby-core

$ jruby –S rake

(in /home/henry/qtjruby/qtjruby-core)

ant -lib /opt/jruby-1.1.2/bin/../lib

Buildfile: build.xml



qtjruby-core:

  [javac] Compiling 14 source files to C:\home\devel\qtjruby\qtjruby-core\build

  [javac] Note: Some input files use unchecked or unsafe operations.

  [javac] Note: Recompile with -Xlint:unchecked for details.

  [jar] Building jar: C:\home\devel\qtjruby\qtjruby-core\lib\qtjruby-core.ja

r



BUILD SUCCESSFUL

Total time: 1 second

WARNING:  no rubyforge_project specified

WARNING:  RDoc will not be generated (has_rdoc == false)

  Successfully built RubyGem

  Name: qtjruby-core

  Version: 0.2.0

  File: qtjruby-core-0.2.0.gem

 /opt/jruby-1.1.2/bin/../bin/jruby -S gem install pkg/qtjruby-core-0.2.0.gem

Successfully installed qtjruby-core-0.2.0

1 gem installed
The Qt::JRuby library includes a Ruby module named
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 6: Build Tools
Inhaltsvorschau
Just about every software project, regardless of language or scope, needs to be built in some way. The build process can include steps including compiling code, running tests, file processing, packaging, and deployment, among others. Because there is significant commonality among build processes, a variety of specialized build systems are available. These systems allow you to describe your build process as a series of interdependent, reusable tasks. Ant, for example, allows you to replace this:
$ javac *.java

$ jar –cf my.jar *.class
With this:
$ ant jar
Or even (if jar is the default target):
$ ant
This chapter discusses techniques for building Java-based projects. In this context, Ruby can be used as the core of the build process or to enhance an existing build process. There are two major build systems used for Java projects: Ant and Maven. Both of these are projects of the Apache Software Foundation and both have extension mechanisms that support JRuby. This is the focus of the first few recipes. The later recipes describe two different Ruby-based build systems designed for Java projects: Raven and Buildr. All four of these build systems have merit: which to use for a particular project is largely a matter of preference. Raven and Buildr are significantly newer than Ant and Maven and, as a result, the communities around them are smaller.
The chapter ends with two recipes about the Hudson continuous integration server. The first of these addresses how to build Ruby projects that use the Rake build system. The second looks at using Ruby to add additional scripting to your build process inside Hudson.
You are using Apache Ant as a build system and need to add some logic to your build that isn’t easily accomplished with Ant’s XML syntax.
Add the appropriate JRuby dependencies to Ant’s lib directory and use the script task to include Ruby code inside your Ant build file. shows a very simple usage of this task.
Example . Hello World from JRuby inside Ant
<?xml version="1.0" encoding="UTF-8"?>

<project name="project" default="package">

    <target name="simple">

        <script language="ruby">

               print "Hello World!"

        </script>

    </target>

</project>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
Just about every software project, regardless of language or scope, needs to be built in some way. The build process can include steps including compiling code, running tests, file processing, packaging, and deployment, among others. Because there is significant commonality among build processes, a variety of specialized build systems are available. These systems allow you to describe your build process as a series of interdependent, reusable tasks. Ant, for example, allows you to replace this:
$ javac *.java

$ jar –cf my.jar *.class
With this:
$ ant jar
Or even (if jar is the default target):
$ ant
This chapter discusses techniques for building Java-based projects. In this context, Ruby can be used as the core of the build process or to enhance an existing build process. There are two major build systems used for Java projects: Ant and Maven. Both of these are projects of the Apache Software Foundation and both have extension mechanisms that support JRuby. This is the focus of the first few recipes. The later recipes describe two different Ruby-based build systems designed for Java projects: Raven and Buildr. All four of these build systems have merit: which to use for a particular project is largely a matter of preference. Raven and Buildr are significantly newer than Ant and Maven and, as a result, the communities around them are smaller.
The chapter ends with two recipes about the Hudson continuous integration server. The first of these addresses how to build Ruby projects that use the Rake build system. The second looks at using Ruby to add additional scripting to your build process inside Hudson.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Adding Ruby Scripting to Ant Builds
Inhaltsvorschau
You are using Apache Ant as a build system and need to add some logic to your build that isn’t easily accomplished with Ant’s XML syntax.
Add the appropriate JRuby dependencies to Ant’s lib directory and use the script task to include Ruby code inside your Ant build file. shows a very simple usage of this task.
Example . Hello World from JRuby inside Ant
<?xml version="1.0" encoding="UTF-8"?>

<project name="project" default="package">

    <target name="simple">

        <script language="ruby">

               print "Hello World!"

        </script>

    </target>

</project>
This task can use either the Bean Scripting Framework (BSF) or the Java Scripting (JSR 223) libraries discussed in and, as a result, supports many more scripting languages than just Ruby. To use this task, you must make the appropriate dependencies available to Ant. For BSF, these dependencies are jruby.jar and bsf.jar, both included in the JRuby distribution’s lib directory. For Java Scripting, you need the jruby.jar file from the JRuby distribution and jruby-engine.jar, available from https://scripting.dev.java.net/. and contain more information about these APIs. As mentioned in the Solution above, these JAR files can be placed in Ant’s lib directory. Alternatively, the dependencies can be declared inside the Ant build file as seen in . This latter method requires slightly more configuration, as you need to set up the appropriate Ant properties—jruby.home and jsr223.engines.home in the case of . In this example, those properties are defined in a build.properties file in the user’s home directory.
Example . Defining JRuby dependencies inside the Ant file
<?xml version="1.0" encoding="UTF-8"?>

<project name="project" default="package">



    <property file="${user.home}/build.properties" />

    <path id="jruby">

        <fileset file="${jruby.home}/lib/jruby.jar" />

        <fileset file="${jsr223.engines.home}/lib/jruby-engine.jar" />

    </path>



    <target name="simple">

        <script language="ruby" classpathref="jruby">

               print "Hello #{$project.getProperty('user.name')}"

        </script>

    </target>

</project>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using Ruby in Ant Conditions
Inhaltsvorschau
Your Ant build has some conditional execution that is best expressed with Ruby code.
Set up the Ant classpath as described in and use the scriptcondition Ant condition element. This element is set up similar to the script task described in . The key distinction is that conditions are evaluated to produce a Boolean result. Typically, the condition has a default value and the content of the condition would override this as necessary. For example, the Ant fragment in will set a property named user_has_text_files to true if the user has any text files in their home directory.
Example . Using scriptcondition
<target name="setup">

    <condition property="user_has_text_files">

        <scriptcondition language="ruby" value="false">

            cwd = Dir.pwd

            Dir.chdir $project.getProperty("user.home")

            $self.setValue(true) if Dir.glob("**/*.txt")

            Dir.chdir cwd

        </scriptcondition>

    </condition>

</target>
In , the default result of the condition is false. This result is overridden to true by using the $self variable, which represents the condition object itself. As with the script task discussed in , the $project variable is set to the Ant Project object and all Ant properties are available as variables in the Ruby script.
Ant conditions can be combined with and, or, not, and xor condition elements. shows the combination of the condition from with one of Ant’s built-in conditions, os. In this example, we ensure that the user_has_text_files property is only set on Windows systems.
Example . Combining scriptcondition with other Ant conditions
<target name="setup">

    <condition property="user_has_text_files">

        <and>

            <os family="windows"/>

            <scriptcondition language="ruby" value="false">

                puts "hello"

                cwd = Dir.pwd

                Dir.chdir $project.getProperty("user.home")

                $self.setValue(true) if Dir.glob("**/*.txt")

                Dir.chdir cwd

            </scriptcondition>

        </and>

    </condition>

</target>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Writing an Ant Task in Ruby
Inhaltsvorschau
You want to execute a Ruby script in multiple Ant build files.
Use Ant’s scriptdef task to create a new task definition that executes a Ruby script. The scriptdef task has a child element named attribute, which can be used to pass attributes into the task. defines an Ant task named start-webrick that can be used to start up an instance of the WEBrick HTTP server given a specific port number and document root.
Example . Using scriptdef to define a new Ant task
<?xml version="1.0" encoding="UTF-8"?>

<project name="project" default="start">



    <scriptdef name="start-webrick" language="ruby">

        <attribute name="port"/>

        <attribute name="root"/>

        <![CDATA[

            require 'webrick'

            include WEBrick



            server = HTTPServer.new(:Port => $attributes.get('port').to_i)

            server.mount("/", HTTPServlet::FileHandler, $attributes.get('root'))

            server.start

        ]]>

    </scriptdef>



    <target name="start">

            <start-webrick port="8000" root="${basedir}/files"/>

    </target>



</project>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Adding Ruby Scripting to Maven Builds
Inhaltsvorschau
You are using Apache Maven as a build system and need to quickly add some additional steps to your build process.
Configure the JRuby Maven plugin in your Maven project definition file, pom.xml. shows the use of this plugin. In this example, the plugin’s run goal, which executes a Ruby script, is bound to the process-resources phase. This means that the inline Ruby script will be run before any compilation or tests occur.
Example . Using the JRuby Maven plugin
<project>

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.jrubycookbook</groupId>

    <artifactId>maven-sample</artifactId>

    <packaging>pom</packaging>

    <version>1.0-SNAPSHOT</version>



    <build>

        <plugins>

            <plugin>

                <groupId>org.codehaus.mojo</groupId>

                <artifactId>jruby-maven-plugin</artifactId>

                <executions>

                    <execution>

                        <phase>generate-resources</phase>

                        <goals>

                            <goal>run</goal>

                        </goals>

                        <configuration>

                            <ruby>

                                require 'fileutils'

                                FileUtils.touch 'target/timestamp'

                            </ruby>

                        </configuration>

                    </execution>

                </executions>

                <!— These are necessary due to an issue with

                    JRuby's Maven distribution. -->

                <dependencies>

                    <dependency>

                        <groupId>backport-util-concurrent</groupId>

                        <artifactId>backport-util-concurrent</artifactId>

                        <version>3.0</version>

                    </dependency>

                    <dependency>

                        <groupId>asm</groupId>

                        <artifactId>asm-all</artifactId>

                        <version>2.2.3</version>

                    </dependency>

                </dependencies>

            </plugin>

        </plugins>

    </build>

</project>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Writing a Maven Plugin with JRuby
Inhaltsvorschau
You are using Apache Maven as a build system and want to reuse some Ruby script across different projects. A good example of this is to use the RedCloth Ruby library for generating project documentation using the Textile markup language.
Create a new Maven plugin project and add the dependencies discussed in to both the project and the maven-plugin-plugin plugin. contains a simple pom.xml project descriptor.
Example . Maven pom.xml file for a JRuby-based Maven plugin
<project>

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.jrubycookbook</groupId>

    <artifactId>maven-textile-plugin</artifactId>

    <packaging>maven-plugin</packaging>

    <version>1.0-SNAPSHOT</version>

    <name>Maven Textile Plugin</name>

    <description>

        Generates site documentation from Textile sources using

        RedCloth.

    </description>

    <dependencies>

        <dependency>

            <groupId>org.codehaus.mojo</groupId>

            <artifactId>jruby-maven-plugin</artifactId>

            <version>1.0-beta-4</version>

        </dependency>

        <dependency>

            <groupId>backport-util-concurrent</groupId>

            <artifactId>backport-util-concurrent</artifactId>

            <version>3.0</version>

        </dependency>

        <dependency>

            <groupId>asm</groupId>

            <artifactId>asm-all</artifactId>

            <version>2.2.3</version>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <artifactId>maven-plugin-plugin</artifactId>

                <dependencies>

                    <dependency>

                        <groupId>org.codehaus.mojo</groupId>

                        <artifactId>jruby-maven-plugin</artifactId>

                        <version>1.0-beta-4</version>

                    </dependency>

                    <dependency>

                        <groupId>backport-util-concurrent</groupId>

                        <artifactId>

                            backport-util-concurrent

                        </artifactId>

                        <version>3.0</version>

                    </dependency>

                    <dependency>

                        <groupId>asm</groupId>

                        <artifactId>asm-all</artifactId>

                        <version>2.2.3</version>

                    </dependency>

                </dependencies>

            </plugin>

        </plugins>

    </build>

</project>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Building Java Projects with Raven
Inhaltsvorschau
You need to build a Java project and wish to write your build script using Ruby rather than XML.
Use Raven, a build tool for Java project that is based on Ruby’s Rake tool. Raven is essentially an add-on to Rake that provides Rake with additional Rake tasks to build Java projects. Raven is available as a RubyGem, so to install it simply run:
$ gem install raven
To use Raven, create a file named Rakefile in the root of your project and include all necessary tasks in this file. contains the simplest of Raven build scripts.
Example . Simple Raven build script
require 'raven'



javac 'compile'
This script would be executed by running:
$ rake compile
Or:
$ jruby -S rake compile
This will compile all the Java files in a directory named src/main/java, following the Maven project convention (see upcoming sidebar). This default can be easily overridden, as seen in .
Example . Changing the default source directory
require 'raven'



javac 'compile' do |t|

    t.build_path << "src/java"

end
Because Raven is based on Rake, any existing Rake task can be used within a Raven build. A good example of this is the clean task. Since Rake includes a clean task, Raven doesn’t need to provide one, as seen in .
Example . Raven build with Rake tasks
require 'raven'

require 'rake/clean'



CLEAN.include('target')



javac 'compile'
Note that Raven actually doesn’t require JRuby.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Referencing Libraries with Raven
Inhaltsvorschau
You are using Raven to build your Java project and depend upon other libraries, such as those from Jakarta Commons.
Use the dependency Raven task to define a set of dependencies and then reference the set from the tasks that need the dependencies. contains a Rakefile for a project that depends upon Jakarta Commons Logging and Jakarta Commons HttpClient. The dependency on the HttpClient library is restricted to version 3.1 by using the => operator.
Example . Rakefile with dependencies
1 require 'raven'

2

3 dependency 'compile_deps' do |t|

4     t.deps << ['commons-logging', {'commons-httpclient' => '3.1'}]

5 end

6

7 javac 'compile' => 'compile_deps'

8

9 javadoc 'jdoc' => 'compile_deps'
When used in a task definition, as on lines 7 and 9 of , the => operator establishes a dependency between tasks.
Raven uses the RubyGems packaging system to manage dependencies by wrapping JAR files into a RubyGem. In order to avoid, in the words of the Raven source code, polluting the regular local RubyGem repository, defined by the GEM_HOME environment variable, Raven stores its RubyGems in a .raven subdirectory of the user’s home directory. As discussed in the sidebar within , it is possible to populate this directory with the contents of a local Maven repository by running:
raven import
The Raven team makes a public gem repository available at http://gems.rubyraven.org/ that contains wrapped versions of all of the libraries in the central Maven repository (http://repo1.maven.org/maven2/). It is possible to set up your own private repository, as we’ll see in the next recipe.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Hosting a Private Raven Repository
Inhaltsvorschau
You are building a Java project with Raven and want to insulate your build process from any external network problems.
Create a private Raven repository by importing content from a Maven repository. This can be done with a few simple commands:
# Change /home/raven below to whatever directory you want to use.

$ mkdir /home/raven

$ cd /home/raven

$ raven repository

$ raven server
This will import all artifacts from the central Maven repository and then start a web server on port 2233. To reference this repository in your Rakefile, add this line after the require statements:
set_sources(["http://localhost:2233"])
The repository command used above has a few interesting options. First, it is possible to restrict the import to a subset of the repository by passing a list of project identifiers to the command. For example, to import only Jakarta Commons HttpClient and JUnit, you would run:
$ raven repository commons-httpclient junit
It is also possible to import a different Maven repository using the -m option. For example, to import JBoss’s Maven repository, run:
$ raven –m http://repository.jboss.com/maven2/ repository
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Running JUnit Tests with Raven
Inhaltsvorschau
You are building your Java project with Raven and want to execute some JUnit unit tests.
Place your unit tests in the src/test/java directory, create a dependency task for any test dependencies, and then use the junit Raven task as seen in . By default, Raven will search for classes whose names start with Test, but in , this default is overridden to include only those classes with names ending with Test.
Example . Unit testing with Raven
require 'raven'



dependency 'compile_deps' do |t|

    t.deps << ['commons-logging', {'commons-httpclient' => '3.1'}]

end



dependency 'test_deps' => 'compile_deps' do |t|

    t.deps << {'junit' => '3.8.2'}

end



javac 'compile' => 'compile_deps'



junit 'test' => ['compile', 'test_deps'] do |t|

    t.test_classes << "**/*Test.java"

end
You will see the test results on the console. If the tests pass, you’ll see an OK message:
$ rake test

(in /home/justin/raven-sample1)

...

Running test org.jrubycookbook.SomeTest

.

Time: 0



OK (1 test)
A test failure will include the stack trace:
$ rake test

(in /home/justin/raven-sample1)

...

Running test org.jrubycookbook.SomeTest

.F

Time: 0

There was 1 failure:

1) testTest(org.jrubycookbook.SomeTest)junit.framework.AssertionFailedError

        at org.jrubycookbook.SomeTest.testTest(SomeTest.java:8)

        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.

java:39)

        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces

sorImpl.java:25)



FAILURES!!!

Tests run: 1,  Failures: 1,  Errors: 0



There were failures!
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Building Java Projects with Buildr
Inhaltsvorschau
You need to build a Java project and wish to define your project’s build using Ruby rather than XML.
Use Buildr, a declarative build system for Java code written in Ruby. Buildr is available as a RubyGem; installation can be done by running:
$ gem install buildr
Buildr uses a file named buildfile to define a project. A minimal buildfile such as the one seen in defines the project’s name (line 11), the project’s group (line 13), a description of the project (line 10), the current version of the project (line 12), and the packaging type of the project (line 14).
Example . Minimal Buildr buildfile
10 desc "The Chapter 6 buildr project"

11 define "ch06-buildr" do

12   project.version = "1.0"

13   project.group = "org.jrubycookbook"

14   package(:jar)

15 end
Based on this buildfile, Buildr will assume that this is a project containing Java sources in a directory named src/main/java and JUnit test cases in a directory named src/test/java. The generated JAR file will be named ch06-buildr-1.0.jar. To build the project (which for Buildr means compiling the source code and running the tests), simply run:
$ buildr
To build the JAR file, run:
$ buildr package
These commands can be run in the project’s root directory or any subdirectory.
If you have an existing Java project, especially one that uses Maven as its build system, Buildr can automatically create this file for you. Run buildr from the project’s root directory and select the appropriate option:
$ buildr

To use Buildr you need a buildfile. Do you want me to create one?:

1. From maven2 pom file

2. From directory structure

3. Skip

?  1

Created /home/edelsonj/kramer/buildfile
When creating a buildfile from an existing Maven project’s pom.xml file, Buildr is able to extract all of the information seen in as well as all of the project’s dependencies. The importer can be a little over-enthusiastic when it comes to dependencies, so always check the resulting buildfile. If your Maven project includes submodules, the generated
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Referencing Libraries with Buildr
Inhaltsvorschau
You are using Buildr to build your Java project and depend upon other libraries, such as those from Jakarta Commons.
Pass the list of dependencies to the compile.with method. Each dependency is defined by four attributes: group, name, packaging type, and version. For example, if your code depends upon Apache HttpClient and Jakarta Commons Logging, you would specify:
compile.with "org.apache.httpcomponents:httpclient:jar:4.0-alpha4",

  "org.apache.httpcomponents:httpcore:jar:4.0-beta1",

  "commons-logging:commons-logging:jar:1.1.1"
Buildr will look for dependencies in your local Maven repository (in the .m2/repository subdirectory of your home directory). If it cannot find the dependencies there, it will attempt to download them from a remote repository. As a result, it is also necessary to add this line to your buildfile:
repositories.remote << "http://repo1.maven.org/maven2/"
Buildr’s dependency mechanism is entirely based upon the Maven repository structure. Unlike Raven, which uses a RubyGems-based dependency mechanism, any library in an existing Maven repository can be used as part of a Buildr build. This includes the libraries in the central repository (at http://repo1.maven.org/maven2/), as well as other public Maven repositories hosted by Sun (http://download.java.net/maven/2/) and JBoss (http://repository.jboss.com/maven2/), among others. Individual developers and software development organizations can also host private Maven repositories.
Although Buildr will sometimes correctly resolve dependencies transitively, this functionality does not always work. Expect support for transitive dependencies to improve in upcoming versions.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Building with Rake Inside Hudson
Inhaltsvorschau
You want to build a software project that uses Rake as its build system in a continuous manner. This could be on a schedule (i.e., every day at noon) or upon every submission to a version control system like Subversion.
Use a continuous integration server that supports Rake, such as Hudson. Once the Hudson Rake plugin is installed, you can simply add a Rake execution to your job, as in .
Figure : Rake build step in Hudson job configuration
To install the Rake plugin in Hudson, use the Hudson Plugin Manager, which can be found under the Manage Hudson menu. Inside the Plugin Manager, select the Available tab to see the list of available plugins. Check the box next to the Rake plugin listing () and click the Install button. After the plugin has been installed, you will need to restart Hudson.
Figure : Rake plugin entry in the Plugin Manager
Hudson’s Rake plugin allows you to configure multiple Ruby runtimes. This allows you to have some projects built against MRI and some projects built against JRuby within the same continuous integration server. This is done through the System Configuration screen, seen in .
Figure : Multiple Ruby runtimes in Hudson
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Adding Ruby Script to a Hudson Job
Inhaltsvorschau
You have some additional build steps that need to be done as part of your build process when executed through the Hudson continuous integration server.
Use the Hudson Ruby plugin. This plugin allows you to add arbitrary Ruby script as a build step in your job. shows a job with two build steps. The first executes the Ant target named war and the second runs some Ruby code that copies all WAR files into a temporary directory.
Figure : Using the Hudson Ruby plugin
As with the Rake plugin discussed in , the Ruby plugin can be downloaded and installed through Hudson’s Plugin Manager. Unlike the Rake plugin, the Ruby plugin does not support multiple runtimes. It will only execute the ruby command on your PATH. Thus, if want to use this plugin with JRuby, it will be necessary to create a copy (or symbolic link) of the jruby script included with the JRuby distribution named ruby and ensure that this script is on your PATH before any other Ruby. The plugin does make debugging simple by outputting the Ruby version number in the build’s console output, like this:
[workspace] $ ruby -v /tmp/hudson35926.rb

ruby 1.8.5 (2007-09-24 patchlevel 114) [i386-linux]
Hudson makes a number of environment variables available to Ruby scripts executed in this manner. These include the name of the job (JOB_NAME), the build number (BUILD_NUMBER), and the Hudson URL (HUDSON_URL). A full listing is available through the Hudson web interface.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 7: Testing
Inhaltsvorschau
The focus of this chapter is the topic of automated testing, specifically, testing Java code with Ruby. There are several key advantages of using a dynamic language, such as Ruby, to test code written in a statically typed language, such as Java:
  • Automated test cases tend to require a lot of bootstrapping code. Using a domain-specific language (DSL) such as those provided by the Ruby frameworks like dust and Expectations can cut down on this repetitive code.
  • Dynamic languages make it very easy to create mock objects. JRuby, for example, allows you to directly instantiate Java interfaces.
  • Open classes allow code to be modified at runtime to facilitate testing.
There are a variety of testing frameworks available in Ruby, the most popular of which are wrapped into a JRuby-based project called JtestR. JtestR is an open source project that Ola Bini and Anda Abramovici, developers at ThoughtWorks, started in 2008 with the purpose of making it easy to test Java code with a variety of Ruby testing frameworks. As of the current version 0.3, JtestR includes support for:
  • Test/Unit
  • RSpec
  • Expectations
  • dust
  • Mocha
In addition, JtestR supports the Java testing frameworks JUnit and TestNG, making it a “one-stop shop” for testing frameworks.
JtestR is available for download from http://jtestr.codehaus.org.
You want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, but with a minimal learning curve for developers familiar with JUnit.
Use JtestR’s support for the Ruby testing framework Test/Unit. Test/Unit uses similar semantics to JUnit: test cases extend a specific test case class and test methods follow a naming convention. In the case of Test/Unit, test cases must extend Test::Unit::TestCase and test methods are prefixed with test_. shows a simple Test/Unit class that tests the size() method of java.util.ArrayList.
Example . Simple Test/Unit
class TestArrayList < Test::Unit::TestCase



 def test_that_size_method_works

    list = java.util.ArrayList.new

    assert_equal(0, list.size)

    list << 'first'

    list << 'second'

    assert_equal(2, list.size)

  end



end
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
The focus of this chapter is the topic of automated testing, specifically, testing Java code with Ruby. There are several key advantages of using a dynamic language, such as Ruby, to test code written in a statically typed language, such as Java:
  • Automated test cases tend to require a lot of bootstrapping code. Using a domain-specific language (DSL) such as those provided by the Ruby frameworks like dust and Expectations can cut down on this repetitive code.
  • Dynamic languages make it very easy to create mock objects. JRuby, for example, allows you to directly instantiate Java interfaces.
  • Open classes allow code to be modified at runtime to facilitate testing.
There are a variety of testing frameworks available in Ruby, the most popular of which are wrapped into a JRuby-based project called JtestR. JtestR is an open source project that Ola Bini and Anda Abramovici, developers at ThoughtWorks, started in 2008 with the purpose of making it easy to test Java code with a variety of Ruby testing frameworks. As of the current version 0.3, JtestR includes support for:
  • Test/Unit
  • RSpec
  • Expectations
  • dust
  • Mocha
In addition, JtestR supports the Java testing frameworks JUnit and TestNG, making it a “one-stop shop” for testing frameworks.
JtestR is available for download from http://jtestr.codehaus.org.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Unit Testing Java Code with Test/Unit
Inhaltsvorschau
You want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, but with a minimal learning curve for developers familiar with JUnit.
Use JtestR’s support for the Ruby testing framework Test/Unit. Test/Unit uses similar semantics to JUnit: test cases extend a specific test case class and test methods follow a naming convention. In the case of Test/Unit, test cases must extend Test::Unit::TestCase and test methods are prefixed with test_. shows a simple Test/Unit class that tests the size() method of java.util.ArrayList.
Example . Simple Test/Unit
class TestArrayList < Test::Unit::TestCase



 def test_that_size_method_works

    list = java.util.ArrayList.new

    assert_equal(0, list.size)

    list << 'first'

    list << 'second'

    assert_equal(2, list.size)

  end



end
Like JUnit, Test/Unit supports the use of a setup method (named setup) into which you can extract code that needs to be executed prior to each test. For example, if a second test method was added to , it would make sense to put the creation of the new ArrayList instance into this setup method, as seen in .
Example . Test/Unit class with setup method
class TestArrayList < Test::Unit::TestCase



 def setup

     @list = java.util.ArrayList.new

 end



 def test_that_size_method_works

     assert_equal(0, @list.size)

    @list << 'first'

    @list << 'second'

    assert_equal(2, @list.size)

  end



  def test_that_empty_works

     assert(@list.empty)

     @list << 'first'

     @list << 'second'

     assert(!@list.empty)

   end



end
Test/Unit also supports the use of a method named teardown for cleanup after each test is run.
Test/Unit tests can be run without any additional configuration with JtestR. Simply place the test class files in a directory named test/unit and start JtestR’s command-line test runner. This class, along with all of JtestR’s dependencies can be found in the JtestR JAR file, available from the JtestR website. You can run the JtestR command-line test runner with the command:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Unit Testing Java Code with dust
Inhaltsvorschau
You want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, and find Test/Unit to be too verbose.
Use Jay Fields’s dust library, support for which is included with JtestR. dust provides an alternate syntax for writing tests that takes advantage of Ruby language features to create a domain-specific language (DSL) for testing. contains the dust version of the tests in .
Example . Unit testing with dust
unit_tests do

    test "that size method works" do

        @list = java.util.ArrayList.new

        assert_equal(0, @list.size)

        @list << 'first'

        @list << 'second'

        assert_equal(2, @list.size)

    end



    test "that empty method works" do

        @list = java.util.ArrayList.new

        assert @list.empty

        @list << 'first'

        @list << 'second'

        assert !@list.empty

    end

end
As with Test/Unit tests, dust tests can be run through JtestR with no special .
Under the covers, dust converts the body of the block passed to the unit_tests method into a Ruby class in the Units module. The name is derived from the filename. If was contained in a file named lists_test.rb, the generated class would be Units::ListsTests. Each call to the test method is converted to a method in this generated class. The name of the method is derived from the name given. The generated class for includes methods named test_that_size_method_works and test_that_empty_method_works.
In addition to the unit_tests method seen in , dust also supports a functional_tests method. The only difference between the two methods is that tests within the functional_tests method are placed in a class in the Functionals module.
Under the default JtestR configuration, these generated class and method names are only seen when a test fails. For example:
Failure:

test_that_size_method_works(Units::ListTests)

...

<2> expected but was

<3>.
Unlike Test/Unit, dust does not support setup or teardown methods.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Unit Testing Java Code with Expectations
Inhaltsvorschau
You want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG and want to ensure you follow some testing best practices, specifically limiting the number of assertions per test to one.
Use JtestR’s support for the Expectations framework. Like dust, Expectations provides a domain-specific language (DSL) for writing tests. Unlike dust, Expectations does not use the standard Test/Unit assertion methods. Instead, each test makes an assertion about the return value of the test. contains the same tests seen in prior recipes using Expectations.
Example . Unit testing with Expectations
Expectations do

    expect 0 do

        list = java.util.ArrayList.new

        list.size

    end



    expect 2 do

        list = java.util.ArrayList.new

        list << 'first'

        list << 'second'

        list.size

    end



    expect true do

        list = java.util.ArrayList.new

        list.empty

    end



    expect false do

        list = java.util.ArrayList.new

        list << 'first'

        list << 'second'

        list.empty

    end

end
JtestR’s support for Expectations is not automatic; it must be enabled through configuration. To do so, first determine the naming convention you will use for Expectations-based tests. Then create a file named jtestr_config.rb in the test directory of your project. This file should contain a line such as the following:
expectation Dir["test/expectations/*.rb"]
In this case, we declare that any file in the test/expectations directory is meant to be run with Expectations. You could also use a filename-based naming convention:
expectation Dir["test/**/*_expect.rb"]
Or even declare individual files:
expectation Dir["test/unit/list_tests_expect.rb"]
The output of Expectations is different than that for Test/Unit or dust tests, but the information conveyed is similar:
Expectations .F.F

Finished in 0.00206 seconds



Failure: 2 failed, 0 errors, 2 fulfilled



--Failures--

file </home/justin/list-tests/test/expectations/test.rb>

line <7>

expected: <3> got: <2>



file </home/justin/list-tests/test/expectations/test.rb>

line <19>

expected: <true> got: <false>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Testing Java Code with RSpec
Inhaltsvorschau
You want to write behavior-orientated tests for your Java code.
Use JtestR’s support for the RSpec Behavior-Driven Development (BDD) framework. RSpec is actually composed of two different frameworks for writing tests: the Spec framework and the Story framework.

Spec framework

RSpec Spec tests describe the behavior of an object through a series of assertions about the behavior of the object. These assertions are referred to as examples. The Spec file in describes the behavior of the java.util.HashSet class.
Example . RSpec Spec file for java.util.HashSet
import java.util.HashSet



describe HashSet do

  before(:each) do

    @set = HashSet.new

  end



  it "should be empty" do

    @set.should be_empty

  end



  it "should be of size one after an item is added" do

      @set << "foo"

    @set.size.should == 1

  end



  it "should be of size one after an item is added twice" do

      @set << "foo"

      @set << "foo"

    @set.size.should == 1

  end



  it "should be of size two after two items are added" do

      @set << "foo"

      @set << "bar"

    @set.size.should == 2

  end

end
By default, JtestR will execute files in any test directory whose filenames end with _spec.rb as an RSpec Spec file. If you place the file from in the unit directory and execute the command-line test runner, you will see output like this:
$ java org.jtestr.JtestRRunner

Unit Spec: 4 examples, 0 failures, 0 errors

Story framework

RSpec stories are generally composed of two files; one that describes the behavior of an object in more-or-less plain text, referred to as the story, and another that translates the behavior descriptions in the first file into method calls on the actual object, referred to as the steps. For example, contains a story that describes the behavior of the retains() method of java.util.ArrayList and contains the steps corresponding to this story. These files are associated with the block at the end of the steps file.
Example . Story about java.util.ArrayList
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Creating Mock Objects with Mocha
Inhaltsvorschau
You want to test a Java class that has dependencies on other classes and want to insulate your tests from changes in the behavior of those other classes.
Use Mocha, a Ruby mocking and stubbing framework that is included with JtestR. Mocha allows you to create instances of Java interfaces and classes that exhibit a specific behavior. Mock objects can be used in any type of test supported by JtestR. In , Mocha is used to create a mock instance of java.util.Collection, which is passed to an instance of java.util.ArrayList. This test validates the behavior of the retainAll() method, specifically that it calls the contains() method on the supplied Collection object the correct number of times.
Example . Unit test with dust and Mocha
unit_tests do

    test "that retainAll only calls contains" do

        list = java.util.ArrayList.new

        list << 'first'

        list << 'second'

        list << 'third'



        other = java.util.Collection.new

        other.expects(:contains).returns(true).times(3)



        list.retainAll(other)

    end

end
If another other method is called on the Collection object, an exception will be thrown and the test will fail. For example, if java.util.ArrayList implemented the retainsAll() method by iterating through the collection, this error would be output:
#<Mock:0x4f4>.contains - expected calls: 1, actual calls: 0
Meaning that the mock expected the contains() method to be called, but that did not occur.
Mocha can also specify the set of parameters to expect. This feature can be used to enhance the test in to test that ArrayList calls the contains() methods in the proper sequence. This new test can be seen in .
Example . Expecting a specific parameter
unit_tests do

    test "that retainAll calls contains once per item in the list" do

        list = java.util.ArrayList.new

        list << 'first'

        list << 'second'

        list << 'third'



        other = java.util.Collection.new

        other.expects(:contains).with('first').returns(true)

        other.expects(:contains).with('second').returns(true)

        other.expects(:contains).with('third').returns(true)



        list.retainAll(other)

    end

end
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Modifying the JtestR Classpath
Inhaltsvorschau
You need to test classes that are not available on JtestR’s default classpath. By default, JtestR’s classpath includes the following directories:
  • build/classes
  • build/test_classes
  • target/classes
  • target/test_classes
The default classpath also includes all JAR files in the lib and build_lib directories (and any subdirectories).
Use the JtestR configuration file, by default named jtestr_config.rb and placed in the test directory, to define the correct classpath. For example, to set the classpath to be the bin directory, your configuration file would contain:
classpath 'bin'
Multiple classpath definitions can be included in the configuration file.
Using the classpath configuration option as described above will overwrite the default classpath. To add the default entries back, put this line to your configuration file:
add_common_classpath true
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Grouping Tests for JtestR
Inhaltsvorschau
You have a number of tests run through JtestR and want to group them.
Follow JtestR’s directory naming conventions to group your tests. Within the main test directory, JtestR will automatically group your tests based on the directory they are in and will execute these groups in a particular order:
  1. Unit tests, those in the unit directory.
  2. Functional tests, those in the functional directory.
  3. Integration tests, those in the integration directory.
  4. Other tests, those that are not in the unit, functional, or integration directories.
The tests within each of these directory-based groups are then further grouped based on the testing framework used. When you run the test runner and have tests in multiple groups, you will see the test results grouped:
Unit TestUnit: 4 test, 0 failures, 0 errors

Integration TestUnit: 2 test, 0 failures, 0 errors
Here we see that there were four tests in the unit directory and two tests in the integration directory, all of which used Test/Unit.
Although JtestR provides these automatic directory-based groups, there is nothing actually different about the environment under which unit tests run as compared with functional or integration tests.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the JtestR Command-Line Options
Inhaltsvorschau
You want to customize the behavior of the JtestR command-line test runner in some way, such as limiting the tests to be run or enabling additional logging.
The JtestR command-line test runner has a number of options that can be configured through command-line arguments. Unfortunately these arguments must be passed in a specific sequence that you must adhere to:
port
This argument, which defaults to 22332, allows you to connect the test runner to a long-lived server process. This reduces the amount of time required to perform a test run. This capability is discussed in .
tests
This argument, which defaults to test, specifies the top-level directory in which test group directories can be found.
logging
This argument specifies the logging level for JtestR. Possible values are NONE, ERR, WARN, INFO, and DEBUG. The default is WARN.
configFile
This argument specifies the filename of the JtestR configuration file.
outputLevel
This argument specifies how much information about each test is output. Possible values are NONE, QUIET, NORMAL, VERBOSE, and DEFAULT.
output
This argument provides JtestR with the output location. The default is STDOUT.
groups
This argument defines the test group (or groups, in which case they should be comma-delimited) that will be run. The default is to run all tests discovered.
One typical use of these arguments is to output the name of each test as it is run. As you can see from the output above, by default, JtestR only outputs an individual test name if something goes wrong. By setting the outputLevel argument to VERBOSE, you can have it output each test name:
$ java org.jtestr.JtestRRunner 22332 test WARN jtsetr_config.rb VERBOSE

test_that_empty_works(TestArrayList): .

test_that_size_method_works(TestArrayList): .

Unit TestUnit: 1 test, 0 failures, 0 errors
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Running JtestR with Ant
Inhaltsvorschau
You are building a project with Apache Ant and want to add tests written in Ruby.
Use the Ant task provided with JtestR. This can be done by adding the following task definition to your Ant build.xml file:
<taskdef name="jtestr"

  classname="org.jtestr.ant.JtestRAntRunner" classpath="lib/jtestr-0.3.jar" />
Then call this task from inside an Ant target:
<target name="test">

    <jtestr />

</target>
This target can then be run from the command line:
$ ant test
The JtestR Ant task supports all of the options used by the command-line test runner (see ). For example, to turn on verbose output, your target would look like this:
<target name="test">

    <jtestr outputLevel="VERBOSE" />

</target>
In addition to the command-line options, there is a failOnError option that defaults to true. Use this option if you want the Ant build to continue even if the tests fail.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Running JtestR with Maven
Inhaltsvorschau
You are building a project with Maven and want to add tests written in Ruby.
Use the Maven plugin provided with JtestR. This can be done by adding the following plugin reference to your pom.xml file:
<plugin>

    <groupId>org.jtestr</groupId>

    <artifactId>jtestr</artifactId>

    <version>0.3</version>

    <executions>

        <execution>

            <goals>

                <goal>test</goal>

            </goals>

        </execution>

    </executions>

</plugin>
Once this is in place, JtestR will automatically run whenever Maven’s test phase is executed.
Unfortunately, the latest release (0.3) of JtestR’s Maven support has a dependency on a nonstandard JRuby library. As a result, when you try to use the plugin, you may see this error:
[ERROR] BUILD ERROR

[INFO] --------------------------------------------------------------

[INFO] Failed to resolve artifact.



Missing:

----------

1) org.jruby:jruby-complete:jar:r6947



  Try downloading the file manually from the project website.

...

----------

1 required artifact is missing.



for artifact:

  org.jtestr:jtestr:maven-plugin:0.3
To correct this, download the JAR from http://dist.codehaus.org/jtestr/jruby-complete-r6947.jar and install it into your local Maven repository. This can be done with these commands:
$ wget http://dist.codehaus.org/jtestr/jruby-complete-r6947.jar

$ mvn install:install-file -Dfile=jruby-complete-r6947.jar -Dversion=r6947 \

 -DartifactId=jruby-complete -Dpackaging=jar -DgroupId=org.jruby
The JtestR Maven plugin supports all of the options used by the command-line test runner (see ). For example, to only run unit tests, your plugin configuration would look like this:
<plugin>

    <groupId>org.jtestr</groupId>

    <artifactId>jtestr</artifactId>

    <version>0.3</version>

    <executions>

        <execution>

            <goals>

                <goal>test</goal>

            </goals>

        </execution>

    </executions>

    <configuration>

        <groups>Unit TestUnit</groups>

    </configuration>

</plugin>
In addition to the command-line options, there is a
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Improving JtestR Performance
Inhaltsvorschau
You are using JtestR and want to accelerate the execution times of your unit tests.
Start a JtestR server in the background. This can be done with the class org.jtestr.BackgroundServer:
$ java org.jtestr.BackgroundServer
By default, this will create a server on port 22332 with two runtimes, meaning that two sets of tests can be run simultaneously. To change these options, you can use command-line arguments: the port followed by the number of runtimes. For example, to start five runtimes listening on port 1000 you would run:
$ java org.jtestr.BackgroundServer 1000 5
Note that if you deviate from the default port, you will need to specify this when you start the test runner. For example, with the command-line test runner, this is the first option:
$ java org.jtestr.JtestRRunner 1000
JtestR also includes classes that allow this test server to be run from inside an Ant or Maven build. For Ant, this is done with the JtestRAntServer class:
<target name="server">

  <taskdef name="jtestr-server"

    classname="org.jtestr.ant.JtestRAntServer" classpath="lib/jtestr-0.3.jar" />

  <jtestr-server />

</target>
For Maven, if you have the JtestR Maven plugin configured in your pom.xml, you can start the server by running this on the command line:
$ mvn jtestr:server
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Chapter 8: The JRuby Community
Inhaltsvorschau
This final chapter includes a series of recipes about how to participate in the JRuby community. First, we will look at building JRuby from source, something that most developers looking to peek under the covers of JRuby will need to do at some point. We will also do a quick walkthrough of JRuby’s issue management system before finishing up with some information about the ways in which JRuby community members communicate with each other.
You need to build JRuby from the source files. This could be to take advantage of some unreleased code or to create a JRuby JAR file for distribution.
Download the source using a Subversion client:
$ svn co http://svn.codehaus.org/jruby/trunk/jruby/
JRuby is built using Apache Ant. There are a number of useful Ant targets in the provided build script:
jar
Creates the jruby.jar file.
jar-complete
Creates the jruby-complete.jar file, which includes all of the contents from jruby.jar and all of the Ruby standard libraries.
test
Runs the JRuby unit test suite.
dist-bin
Creates the JRuby binary distribution, i.e., the ZIP file that you download from http://dist.codehaus.org/jruby/.
The Subversion command above will check out the most recent version of the source code (the trunk) from the JRuby repository. However, some times it is necessary to check out the source core that corresponds to a release. This can be done by checking out one of the tags under http://svn.codehaus.org/jruby/tags/. For example, the source of the JRuby 1.1 release can be found at http://svn.codehaus.org/jruby/tags/jruby-1_1/.
The Ant script also includes two targets that relate to JRuby’s compatibility with other Ruby interpreters. Although there is no formal language specification for Ruby, a wide-ranging test suite has been created as part of the Rubinius project. JRuby’s Ant script includes the following targets that relate to these specifications:
spec
Test all of the released specifications that JRuby is known to be able to pass.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Introduction
Inhaltsvorschau
This final chapter includes a series of recipes about how to participate in the JRuby community. First, we will look at building JRuby from source, something that most developers looking to peek under the covers of JRuby will need to do at some point. We will also do a quick walkthrough of JRuby’s issue management system before finishing up with some information about the ways in which JRuby community members communicate with each other.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Building JRuby from Source
Inhaltsvorschau
You need to build JRuby from the source files. This could be to take advantage of some unreleased code or to create a JRuby JAR file for distribution.
Download the source using a Subversion client:
$ svn co http://svn.codehaus.org/jruby/trunk/jruby/
JRuby is built using Apache Ant. There are a number of useful Ant targets in the provided build script:
jar
Creates the jruby.jar file.
jar-complete
Creates the jruby-complete.jar file, which includes all of the contents from jruby.jar and all of the Ruby standard libraries.
test
Runs the JRuby unit test suite.
dist-bin
Creates the JRuby binary distribution, i.e., the ZIP file that you download from http://dist.codehaus.org/jruby/.
The Subversion command above will check out the most recent version of the source code (the trunk) from the JRuby repository. However, some times it is necessary to check out the source core that corresponds to a release. This can be done by checking out one of the tags under http://svn.codehaus.org/jruby/tags/. For example, the source of the JRuby 1.1 release can be found at http://svn.codehaus.org/jruby/tags/jruby-1_1/.
The Ant script also includes two targets that relate to JRuby’s compatibility with other Ruby interpreters. Although there is no formal language specification for Ruby, a wide-ranging test suite has been created as part of the Rubinius project. JRuby’s Ant script includes the following targets that relate to these specifications:
spec
Test all of the released specifications that JRuby is known to be able to pass.
spec-all
Test all of the released Ruby specifications.
spec-show-excludes
List the specifications that JRuby is known to not be able to pass.
spec-latest
Test all of the available Ruby specifications that JRuby is known to be able to pass, first obtaining the specification files from source control.
spec-latest-all
Test all of the available Ruby specifications, first obtaining the specification files from source control.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Submitting an Issue Report for JRuby
Inhaltsvorschau
You have discovered a problem with JRuby or wish to request a feature to be added in a future version.
JRuby uses Atlassian JIRA as its issue-tracking tool. You can view the list of issues and create new issue reports by going to http://jira.codehaus.org/browse/JRUBY. You can browse issues anonymously, but must register and log in before creating a new issue or commenting on an existing issue. Before creating an issue, please search previously submitted issues to avoid duplication.
Assuming you want to create an issue and have logged in, click the Create New Issue link in the main navigation to start the issue creation process. shows the resulting dialog.
Figure : JIRA Create Issue dialog
Once you have selected the appropriate issue type and clicked Next, you should populate the following form with as much information as possible. This will assist JRuby developers in fully understanding the issue.
At the bottom of the Issue Details form are two form fields, seen in , that provide you with an opportunity to prioritize the handling of your issue.
Figure : Testcase and Patch form fields
The first, “Testcase included,” allows you to specify that you have attached (or will attach) a test that demonstrates the issue in a repeatable manner. The ability to reliably reproduce an issue is vital to resolving it. The second, “Patch Submitted,” allows you to specify that you have attached (or will attach) a patch to the JRuby source that resolves the issue. It is common to create a patch against the latest source from version control, not the most recent release.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Using the JRuby Mailing Lists
Inhaltsvorschau
You need assistance with JRuby or a related tool.
Subscribe to the JRuby User mailing list. Subscriptions are managed through Xircles, a project management system developed for use by the Codehaus. You can see the available JRuby mailing lists by going to http://xircles.codehaus.org/projects/jruby/lists. A searchable archive of the mailing list is also available on this page.
In addition to the mailing lists, JRuby core developers can frequently be found in the #jruby IRC channel on irc.freenode.net. Conversations on this channel are logged and an archive is available through http://codingbitch.com/irc/channel?channel=%23jruby.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
	

Zurück zu JRuby Cookbook


Themen

Buchreihen

Special Interest

International Sites

O'Reilly China O'Reilly USA O'Reilly Japan O'Reilly Taiwan