AntBuilder ant scripts in JRuby

Project Home Page at

Quick start for Windows XP

Common optional extras:

Getting Started with your own JRuby ant scripts

See the examples:



To subclass or not to subclass AntBuilder

If you do not want to subclass AntBuilder then you have to say:

require 'builder/antbuilder'

ant =  
ant.copy(:todir => @jruby_classes_dir) {
  ant.fileset(:dir => @src_dir, :includes => "**/*.properties")

(You don't have to use the name 'ant'; its just an example)

If you *do* subclass AntBuilder then you can don't have to use the 'ant' prefix all over the place.

class Build < Builder::AntBuilder

  def compile_tasks # Builds the Ant tasks that we need later on in the build
    copy(:todir => @jruby_classes_dir) {
      fileset(:dir => @src_dir, :includes => "**/*.properties")



Ant properties and Ant property Files

After every ant command is executed, AntBuilder retrieves the ant properties that have changed since the last command and copies them to ruby instance variables. (Remember that ant properties can only be assigned once).

Properties such as "build.dir" are converted to @build_dir. Any characters in the ant property that are not legal in a ruby instance variable are converted to underscores.

In ant xml build files you will often see:

You can try this in AntBulder with

If the file contains



Then the ruby instance variables defined will be the equivalent of:



(Of course you could always define build_dir and classes_dir rather than build.dir and classes.dir in the file)

You cannot use the ant properties in the ant commands in the ${property} form. ${property} works in ant xml files and replaced by the ant xml file preprocessor.

But you can use the #{@property} form instead in JRuby code. There are a couple of exceptions – firstly the task will process ant properties of the form ${property} in the properties file as shown above (classes.dir=${build.dir}/classes).

Another case where 'native' ant properties can be used is shown here:

available(:property=>"jdk1.4+", :classname=>"java.lang.CharSequence")
patternset(:id => "java.src.pattern") {
  exclude(:unless=>"jdk1.4+", :name=>"**/")

The above code will also create a ruby instance variable called @jdk1_4_

Ant dependencies

def compile # Compile the source files for the project
  depends :compile_tasks, :check_for_optional_packages 
    :destdir => @jruby_classes_dir, 
    :debug => "true", 
    :source=> @javac_version, 
    :classpathref => "build.classpath" 
  ) {
    src(:path => @src_dir)
    patternset(:refid => "java.src.pattern")


The ant taskdef task can be used but the classpath attribute is ignored. If you actually want to use the declared task, you have to make sure that the class is on the classpath.

taskdef(:name =>"jruby_serialize", :classname=>"org.jruby.util.ant.JRubySerialize") {
  classpath(:path => @jruby_classes_dir) # ignored
jruby_serialize(:destdir => @jruby_classes_dir, :verbose=>"true") {
  fileset(:dir => @src_dir) {


If you subclass AntBuilder then you can end the class definition with run_targets_from_command_line and it will run tasks from the command line like ant does.

class Build < Builder::AntBuilder

  def compile_all

  def clean 



Then from the command line you could say:

jruby build.rb clean compile_all

Current Limitations and Gotchas

The AntBuilder project uses the excellent leafcutter api and is influenced by its features:

Common AntBuilder Errors

How Does It Work?

AntBuilder is just a tiny bit of JRuby glue, that sticks together apache-ant, leafcutter and Builder::XMLBase. It relies heavily on Builder::XMLBase to generate the correct syntax for the leafcutter ant api.

Very briefly: When you say "echo(:text => 'starting-build')" there is no such method as echo defined in the class, and this event gets trapped in Builder::XMLBase. The missing method and its parameters are then converted to a string "echo text=starting-build" by XMLBase and the AntBuilder subclass. This string is compatible with the leafcutter api syntax for executing ant code. The string is passed over to leafcutter for execution.


First came Groovy's markup concept: See which was an inspired idea. This inspired Ruby's Builder(and ::XmlMarkup) ( See for the story and the subsequent namespace issue solution which stung Groovy in the tail big time recently. Basically the Builder concept can be applied to any semi hierarchical structure, such as Swing gui construction and ant scripts. Groovy uses this concept to very good effect with its AntBuilder, SwingBuilder, and SWTBuilder. See for an excellent example of the Groovy AntBuilder concept in practice.

Other Alternatives to AntBuilder in the Java world

import org.leafcutter.core.TaskRunner;

public class MyBuild {

public static void main(String[] args) {"copy file=hello.txt tofile=world.txt overwrite=true”);



Other Alternatives to AntBuilder in the Ruby world

Use Rake

Using the Ruby Eclipse plugin with JRuby (Experimental)

Get eclipse 3.1 (or 3.2M3+)

Get the JRuby HEAD (The interpreter from version 0.8.2 will NOT work in RDT)

Install RDT nightly build from

Restart Eclipse

Windows-Preferences-Ruby-Installed-Interpreters and add the JRuby jruby.bat as an interpreter.

Eclipse 3.1 (Windows XP) AntBuilder Developer Setup

Get eclipse 3.1 or 3.2M3+

Get the JRuby HEAD (The interpreter from version 0.8.2 will NOT work in RDT)

Install RDT nightly build from

Restart Eclipse

Windows-Preferences-Ruby-Installed-Interpreters and add the JRuby jruby.bat as an interpreter.

Install cygwin (including ssh from category “Net” - ssltools)

Open eclipse

Menu-Window-Preferences-Team-CVS-Ext Connection Method


Parameters: -l anonymous

CVS Server:cvs

Then open the CVS perspective and set up a new repository::

Expand HEAD and right click AntBuilder and check out as project.

Run the examples

If classes are missing, modify the jruby.bat classpath