I need help with one of the Groovy 1.8 DSL features.
Consider this test case:
开发者_Go百科/**
* For odd number of elements, treat the last element as a call to a getter
*
* case a b c
* equivalent a(b).getC()
*/
void testTrailingElementAsGetter() {
def drank = false
def more = 'more'
def drink = { String s -> [milk: { drank = true }()] }
def d = drink more milk
assert drank
}
If I change [milk: { drank = true }()]
to [foo: { drank = true }()]
, the test case still passes. Could this be a bug in the new implementation or am I missing something in the Groovy syntax?
EDIT - SOLVED: Both @han and @Gareth Davis posted the right clues. Here are some more details to understand this test:
groovy:000> more = 'more'
===> more
groovy:000> drank = false
===> false
groovy:000> drink = { String s -> [milk: { drank = true }()] }
===> groovysh_evaluate$_run_closure1@20c87621
[A] groovy:000> drink more
===> {milk=true}
[B] groovy:000> drank
===> true
groovy:000> drink more milk
===> true
groovy:000> drink more water
===> null
Line [A]
returns a map as @han pointed out. In line [B]
, drank
is already true
, due to the closure executing immediately after creation (as @Gareth Davis pointed out), similar to the JavaScript module pattern. I don't think this "test" is the best way to showcase this feature - the side-effect on drank
is mis-leading.
the problem is in:
def drink = { String s -> [milk: { drank = true }()] }
change to:
def drink = { String s -> [milk: { drank = true }] }
The trailing parens where actually calling the closure on creation rather than on running the DSL.
def d = drink more milk
// d is actually a closure not a boolean you would need to invoke it in order to get the required side effect of setting drank.
d.call()
groovy:000> drank =false
===> false
groovy:000> d = {x -> [y: {drank=true}()]}
===> groovysh_evaluate$_run_closure1@170b819
groovy:000> drank
===> false
groovy:000> d 2
===> {y=true}
groovy:000> drank
===> true
x on first invoke sets drank to true then becomes just a map {y : true}
quite a puzzling behaviour really
from this we can see there are many ways to synthesize a DSL from the new 1.8 syntax - key-dereferencing maps - closure and call - class and method
be bary
精彩评论