我需要一个Groovy 1.8 DSL功能的帮助。
考虑this测试用例:
/**
* 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
}
如果我将[milk: { drank = true }()]
更改为[foo: { drank = true }()]
,则测试用例仍会通过。这可能是新实现中的错误还是我在Groovy语法中遗漏了什么?
编辑 - 已解决:@han和@Gareth Davis都发布了正确的线索。以下是了解此测试的更多细节:
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
行[A]
返回@han指出的地图。在[B]
行中,drank
已经true
,因为创建后立即执行关闭(正如@Gareth Davis指出的那样),类似于JavaScript module pattern。我不认为这种“测试”是展示此功能的最佳方式 - drank
的副作用是错误的。
答案 0 :(得分:2)
问题在于:
def drink = { String s -> [milk: { drank = true }()] }
更改为:
def drink = { String s -> [milk: { drank = true }] }
实际上在创建时调用闭包而不是运行DSL的尾随parens。
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()
答案 1 :(得分:1)
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
第一次调用时的设置为drank然后变成一个地图{y:true}
非常令人费解的行为
从中我们可以看到 有许多方法可以从新的1.8语法合成DSL - 密钥解除引用映射 - 关闭和通话 - 类和方法要小便