Aug 132010
 

One of the things that Groovy is really great at is creating Domain Specific Languages (DSL) or Builders.

When creating a builder I wanted to construct the builder and pass in a closure all in one shot.
While what I was looking for can’t quiet be done (something to do with inner classes so far as I can tell):

def a = new A() { 
    println 'Hi' // error: unexpected token: println 
}
 
// While we can pass a closure as an argument this simply doesn't cut it for a DSL.
def cl = { println 'Hi' }
def b = new A(cl)

Using the with or identity methods comes pretty close:

class A {
 
    def x = 2
 
    def A() {
        println 'Constructor called'
    }
 
}
 
def a = new A().with { obj ->
    println 'Closure called'
    obj.x = 3
    return obj
}
 
println a.x

Output:

Constructor called
Closure called
3

In the case of a builder the other option is to use the provided call method or provide a more domain specifically named build method:

class A {
 
    def x = 2
 
    def A() {
        println 'Constructor called'
    }
 
    def call(Closure cl) {  
        handleClosure(cl)
    }
 
    def build(Closure cl) {
        handleClosure(cl)
        return this // Must return this object not the result of the closure call.
    }
 
    private handleClosure(Closure cl) {
        cl.delegate = this
        cl.resolveStrategy = Closure.DELEGATE_FIRST // Allows the closure to access properties directly.
        cl.call()
    } 
 
}
 
// Option 1, note that a{ } is equivalent to a.call() { }
def a = new A()
a {
    println 'Closure called'
    x = 3
}
 
assert a.x == 3
 
// Option 2, a more DSL method and naturally overloads that take args are possible: build(args) { }.
def b = new A().build {
    println 'Closure2 called'
    x = 4
}
 
assert b.getClass() == A
assert b.x == 4

Now we have the beginnings of a builder. To really give the builder some dynamic attitude you’ll want to take a look at invokeMethod, getProperty, propertyMissing and methodMissing.

Gavin Kromhout:


Thank you for visiting.
Do look around.
Do leave a comment.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)