views:

44

answers:

1

In the code presented here: Gant file, there is the following code:

target(dist: 'Create release artefacts') {
        depends(test)
        depends(jar)
}
target(run: 'Run the distributed jar') {
        depends(dist)
        Ant.java(jar: distributedJarPath, fork: 'true')
}

target(hello: 'Hello World') {
        println("Hello World")
}

setDefaultTarget(dist)

I'm interested in how it's able to write setDefaultTarget(dist), and not receive an exception about dist as a missing property. Is this snippet evaluated in the context of some object, and the targets create instance variables?

+1  A: 

There are two items you need to consider, the Binding of the script, and how a target is declared.

First there is the binding. A Groovy script is a bit different from a Groovy/Java class. Groovy scripts allow for unbound variables. Meaning when you compile the script the variable need not be declared. When the compiler sees one of these undeclared variable references, it will convert the refrence to the variable under the covers to a call to binding.getVariable(variable name) (or something thereabout). So the last line of the script is functionally equivilant to

setDefaultTarget(binding.getVariable('dist'))

Second there is the is the declaration of the target. When the target is declared the Groovy compiler is actually seeing a method call: target(Map args, Closure closure) (or thereabout). When this method executes it examines the args, extracts the name of the target, and stores some wrapped reference to the closure by that name in the binding. An appropximation would be..

target(Map args, Closure closure) {
  binding.setVarialbe( 
    args.keySet().iterator().next(),
    gantClosureWrapping(args, closure))
}

Of course the above code is an approximation and not the real gant code.

so in essence...

target(dist: 'doc') { ... }
// the above adds 'dist' as a variable to the binding

//...

setDefaultTarget(dist)
// dist is unbound, so it is replaced with binding.getVariable('dist')
shemnon