Groovy DSL:我如何让两个委托类处理DSLScript的不同部分?

时间:2015-04-30 12:33:30

标签: groovy dsl

我们说我有这样的DSL

setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "I'm doing dsl stuff"}

可以有一个授权类来实现方法' setup'和' doStuff'通常。在旁边,可以编写要执行的常见Groovy代码(println ...)。

我正在寻找的是一种分两步执行的方法。在第一步中,只应处理设置方法(既不是println)。第二步处理其他部分。

目前,我有两个委派课程。一个实现'设置'另一个实现' doStuff'。但是当然都执行println语句。

1 个答案:

答案 0 :(得分:1)

您可以创建一个类来拦截脚本中的方法调用,并让它协调以下方法调用。我是通过反思来做到的,但如果你愿意,你可以去声明。这些是模型和脚本类:

class FirstDelegate {
  def setup(closure) { "firstDelegate.setup" }
}

class SecondDelegate {
  def doStuff(closure) { "secondDelegate.doStuff" }
}


class MethodInterceptor {
  def invokedMethods = []

  def methodMissing(String method, args) {
    invokedMethods << [method: method, args: args]
  }

  def delegate() {
    def lookupCalls = { instance ->
      def invokes = instance.metaClass.methods.findResults { method ->
        invokedMethods.findResult { invocation ->
          invocation.method == method.name ? 
              [method: method, invocation: invocation] : null 
        }
      }

      invokes.collect { invoked ->
        invoked.method.invoke(instance, invoked.invocation.args) 
      }
    }

    return lookupCalls(new FirstDelegate()) + lookupCalls(new SecondDelegate())
  }
}

这是脚本和断言:

import org.codehaus.groovy.control.CompilerConfiguration

def dsl = '''
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "Ima doing dsl stuff"}
'''


def compiler = new CompilerConfiguration()
compiler.scriptBaseClass = DelegatingScript.class.name

def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)

script = shell.parse dsl

interceptor = new MethodInterceptor()

script.setDelegate interceptor

script.run()

assert interceptor.invokedMethods*.method == [ 'setup', 'doStuff' ]

assert interceptor.delegate() == 
    ['firstDelegate.setup', 'secondDelegate.doStuff']

请注意,我没有打扰println拦截DefaultGroovyMethods,因此处理起来会更加麻烦。

同时让MethodInterceptor类实现方法delegate()不是一个好主意,因为这允许用户定义的脚本来调用它。