Groovy for Domain-specific Languages - Second Edition

(nextflipdebug2) #1

Power Groovy DSL Features


[ 178 ]

Coming back to our markup processing, the next line of code is in the context of a
closure within a closure:


name(firstName:"Fred",surname:"Flintstone")

At this level of nesting, delegate would normally refer to the enclosing
script or instance object. Once again MarkupBuilder has reassigned delegate
to refer to itself. With this, Closure relays the invocation up to its delegate,
MarkupBuilder.invokeMethod() handles it and again pretends it has a
method MarkupBuilder.name(Map m, Closure c).


With each of these pretended methods, MarkupBuilder outputs a tag with the
name of the method and attributes set according to the named parameters, and
then calls the closure. As with most things in Groovy, building your own builder
is surprisingly easy when you know how to do it:


class PoorMansTagBuilder {
int indent = 0
Object invokeMethod(String name, Object args) {
indent.times {print " "}
println "<${name}>"
indent++
args[0].delegate = this // Change delegate to the builder
args[0].call()
indent--
indent.times {print " "}
println "</${name}>"
}
}

given:
def builder = new PoorMansTagBuilder ()

when:
builder.root {
level1{
level2 {
}
}
}

http://www.ebook3000.com
Free download pdf