Groovy Sneak Peak: The DelegatingScript Base Class

As shown by Guillaume Laforge at Gr8Conf 2013 in Copenhagen, Groovy 2.2 will come with a neat feature for writing custom DSL Groovy scripts: the DelegatingScript base class.

Groovy Scripts FTW

One way to write Groovy code is within so-called "scripts". At runtime, Groovy script code is converted to a Script [2] descendant class and an instance of that class is created. I nice tool to actually see the generated classes (and even byte-code) is the groovyConsole's AST browser bundled amongst other useful programs with the Groovy distribution. In the AST browser window you see our script class get's a randomly generated name and it is derived from groovy.lang.Script.

Changing the Base Class

A nice way to further customize custom Groovy scripts is to set a custom base class. A custom base class can be used to provide "global" methods and variables that might be shared within a group of scripts. For example, let's assume we wanted to write a bunch of Robot DSL scripts, we would create a custom base class containing the DSLs variables and functions. In order to set a custom script base class, we need to create an instance of CompilerConfiguration and run the script with that instance.
 

CompilerConfiguration cc = new CompilerConfiguration();
cc.setScriptBaseClass(DelegatingScript.class);

GroovyShell sh = new GroovyShell(cl, new Binding(), cc);
DelegatingScript script = (DelegatingScript)sh.parse(new File("my.dsl"))

// setting the delegate object here!

script.setDelegate(new RobotDSL());

script.run();
 
There are two important lines in the example above. First, a CompilerConfiguration is created to set Groovy's new DelegatingScript as the script's base class. And, using DelegatingScript#setDelegate(Object) the actual delegate object - the object to which all calls are delegated first - is set. Assuming our RobotDSL class looks like this:
 

class RobotDSL {

    def robot = [:]

    def createRobot(Closure c)  {
        robot = [:]
        c.delegate = robot
        c.resolveStrategy = Closure.DELEGATE_ONLY
        c()

        robots << robot
        robot
    }

    def steps(int number) {
        new Movement(number)
    }

    static class Movement {
        def moveLeft(int steps) {
            // move the robot to the left

        }

        def moveRight(int steps) {
            // move the robot to the right

        }
    }
    // ...

}

 
we can write the following DSL script code without having to explicitly specify the delegate object:
 

createRobot {
    name = 'André'
}

steps 4 moveLeft
steps 2 moveRight

 
As can be seen above, DelegatingScript provides a nice way for DSL scripts to remove all DSL setup code to the outside of the script.

Conclusion

Groovy 2.2 comes with a nice feature to automatically delegate all calls in a script to a dedicated delegate object: the DelegatingScript base class.
[1] Groovy Goodness, MrHaki: Using Groovy for Git Hooks
[2] groovy.lang.Script