Groovy / Grails:如何在不破坏DSL的情况下组合闭包

时间:2013-08-27 04:07:18

标签: grails groovy closures dsl

我想知道如何从一个与DSL一起使用的闭包中调用一个闭包。例如,让我们使用Grails的RestBuilder插件。

想象一下,我连续几个街区如:

rest.post("http://my.domain/url") {
    auth(username, password)
    contentType "text/xml"
    body someContent
}

...唯一改变的是someContent。每次调用authcontentType以及body都会重复。所以我想做点什么:

def oauth = [clientId: 'c', clientSecret: 's']

def withAuth(Closure toWrap) {
    Closure wrapped = { it ->
        auth(oauth.clientId, oauth.clientSecret)
        contentType "text/xml"
        toWrap.call()
    }
    return wrapped
}

rest.post("http://my.domain/url") (withAuth {
    body someContent
})

现在,我希望wrappedtoWrap能够访问auth DSL中定义的contentTypeRestBuilder。有没有办法通过设置所有者,代表等来实现这一目标?

(注意:我在上面的例子中理解,我可以声明一个以URL +内容为参数的函数,只需在函数内调用rest.post。我的问题更为通用 - 我是我希望能够更广泛地应用语言和功能技术。)

2 个答案:

答案 0 :(得分:3)

感谢@ igor-artamonov,我有以下工作方法。请注意,我将withAuth从函数更改为闭包,以便它可以访问脚本级状态而无需在脚本上声明@Field变量。

def oauth = [clientId: 'c', clientSecret: 's']

def withAuth { Closure toWrap ->
   return { 
      auth(oauth.clientId, oauth.clientSecret)
      contentType "text/xml"
      toWrap.delegate = delegate
      toWrap.call()
   }
}

rest.post("http://my.domain/url", withAuth {
    body someContent
})

答案 1 :(得分:1)

您可以利用foo(params) { ... }的语法是foo(params, { ... })的语法糖这一事实:

def c = { oauth, b ->
   auth(oauth.clientId, oauth.clientSecret)
   contentType "text/xml"
   body b
}

...

def doPost(String body) {
   rest.post("http://my.domain/url", c.clone().curry(oauth, body))
}

每次克隆闭包都会阻止过时状态,并且currying值会将它们缓存在闭包中,以便它们在Rest构建器调用时可用。