Groovy在Groovy闭包中使用DSL评估字符串

时间:2017-01-23 19:16:57

标签: groovy closures eval

这类似于Need Groovy syntax help for generating a Closure from a String,但有点复杂:

我正在使用我无法控制的复杂DSL(Jenkins Job DSL,特别是,但是为了清晰起见我使用的是假设的DSL)并且我将我的代码分解为返回的闭包。在此代码中不以“my”开头的所有闭包都是假设的DSL:

//scriptContext is a reference to the original script as this is a util class
static def myMethod(def scriptContext) {
    //everything here comes from some hypothetical DSL
    scriptContext.diningTable() {
        ....
        fruits myCreateFruitsClosure()
        ....
    }
}    
static def myCreateFruitsClosure() {
   return {
       apple('Gala') {
           seed("brown")
           shape {
              funky()
              dimpled()
           }
       }
   }
}

以上工作正常。

现在让我们说我希望动态指定apple的详细信息并从某个地方加载一些groovy代码(例如,XML)。

现在我有:

// I pass in the script context for the binding
static def myCreateFruitsClosure(def scriptContext) {
   return {
       apple('Gala') {
           // This comes from somewhere in real life:
           def code = """seed("blue"); shape { oval() ; cardioid() }"""
           def evalWrapper = new GroovyShell(context.binding).evaluate(' { -> ' + code + '}')                      
           evalWrapper()
       }
   }
}

我得到“没有签名方法:Script1.seed()”显然,seed()方法在不使用eval时确实存在,因为它之前有效,所以我的上下文/范围是错误的

我试过了:

  • Eval.me()和Script.evaluate()
  • 的各种组合
  • 创建方法并在evaluate()
  • 内外运行它们
  • 将“createFruitsClosure()”的内容直接移至“myMethod()”

所有这些产生的误差略有不同。什么是正确的方式?

1 个答案:

答案 0 :(得分:2)

最终我的工作

  1. 切换到开放代码块而不是闭包
  2. 明确引用"所有者"从动态代码,并通过绑定使其可用。在这个例子中," self",它是所有者,是苹果关闭。
  3. 结果如下:

    static def myCreateFruitsClosure() {
        return {
            apple {
                def code = """
                    L:{
                       self.seed("blue")
                       self.shape {
                           oval()
                           cardioid()
                       }
                    }"""  
                // sometimes "self: delegate" is appropriate instead of this:
                new GroovyShell(new Binding([self: owner])).evaluate(code)
            }
        }
    }
    

    我想这比我想做的更简单。注意" L:"强制evaluate()将代码视为开放代码块而不是闭包。

    如果有人有更好的方法,请告诉我,但这很有效。