AST Transformations
[ 194 ]
if (!(nodes[0] instanceof AnnotationNode)) return
if (!nodes[1] && !(nodes[1] instanceof ClassNode)) return
ClassNode classNode = nodes[1]
def astNodes = new AstBuilder().buildFromSpec {
method( 'prettyPrint', Opcodes.ACC_PUBLIC, String) {
parameters {}
exceptions {}
block {
owner.expression.addAll
new AstBuilder().buildFromCode {
this.properties.sort { it.key }.each {
if (it.key != 'prettyPrint' &&
it.key != 'class')
println it.key + ": " + it.value
}
}
}
annotations {}
}
}
def methodNode = astNodes[0]
classNode.addMethod(methodNode)
}
}
Using this AST DSL, you can build almost any AST element you need. One
disadvantage, however, is that the DSL is poorly documented, and it also tends to
be subject to change between major Groovy versions. The best way that I've found
of working with this DSL is to dig into the unit tests for the DSL itself. The tests
demonstrate most of the capabilities of the DSL and will give you an insight into how
to use them. See https://github.com/groovy/groovy-core/blob/master/src/
test/org/codehaus/groovy/ast/builder/AstBuilderFromSpecificationTest.
groovy.
Traits to the rescue
In the previous chapter, we encountered traits. We used a trait to apply pretty
printing capabilities to a class. To do this, we needed to have our class implement
the trait class. This means that pretty printing is a compile time dependency, which
means the trait needs to be added to the class in the source code. The big benefit of
the trait is the fact that we can neatly package the functionality we want to add into a
trait class.
http://www.ebook3000.com