开发者

Groovy 1.8 a b c style

开发者 https://www.devze.com 2023-03-19 12:26 出处:网络
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

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

0

精彩评论

暂无评论...
验证码 换一张
取 消