Groovy for Domain-specific Languages - Second Edition

(nextflipdebug2) #1
Chapter 11

[ 283 ]

The only word of caution to heed is that while using both this style of block and the
previous in a single DSL, users will need to beware of the subtle difference between
block {} and block = {}. Groovy allows a user to specify either, and this can give
unexpected results that might be confusing to the general user.


Using binding properties to form context

Most DSLs need to have some predetermined knowledge of the domain within
which they operate. So, for instance, if we were to write a DSL that described the
rewards that a user might get for making purchases, it makes sense that the DSL
would have built-in access to the user's account details and his purchasing history,
rather than requiring complex lookups to be performed within the DSL.


The binding is the ideal place in which to store these details. Depending on the
sophistication of the DSL target audience, we could decide to embed existing domain
objects in the binding or, alternatively, we could look up or pre-calculate values that
make sense to the DSL, and embed these.


class Account {
double spend = 11.00
double balance = 100.00
boolean active = true

void credit (double value) {
balance += value
}
}
def binding = new Binding()
binding.reward = { closure ->
closure.delegate = delegate
closure()
}

binding.apply = { closure ->
closure.delegate = delegate
closure()
}

// lookup account in binding
def account = new Account()
binding.account = account
binding.monthSpend = account.spend
binding.credit = account.&credit
Free download pdf