groovy命令表达式如何做嵌套表达式?

时间:2012-02-18 16:04:41

标签: groovy dsl

我正在使用Groovy开发一个漂亮的小DSL。

我非常喜欢具有更高阶函数的Command Expression。

我可以做的代码很少:

timerange = from today to tomorrow

这实际上是

timerange = from(today).to(tomorrow)

但现在我想做这样的事情:

difference = difference from today to tomorrow

应该会产生这样的结果:

difference = difference(from(today).to(event.start))

我总是得到错误:

  

没有这样的属性:from for class:Script1。

这是一个带有main方法的测试类。第三个断言失败了:

任何人都可以告诉我一个如何做到这一点的例子吗?

import groovy.time.DatumDependentDuration

/**
 * Created by IntelliJ IDEA.
 * User: nils
 * Date: 2/18/12
 * Time: 4:41 PM
 */
class SimpleTest {

    def static today = new Date();
    def static tomorrow = new Date() + 1;

    def loadDSL(Closure cl) {

        cl.delegate = this
        return cl()

    }

    def toMethod = { date ->
        [to: { timeThing ->
            if (timeThing instanceof Date) {
                use(groovy.time.TimeCategory) {
                    (date..timeThing) //return Range
                }
            }
        }]
    }

    def from(Date date) {
        toMethod(date)
    }

    def difference(Range range) {
        range.size() //for the sake of simplicity
    }

    static void eval(dslContent, assertion) {
        SimpleTest runner = new SimpleTest()
        def dsl = """
      run {
        ${dslContent}
      }
    """

        def binding = new Binding()
        binding.run = { Closure cl -> runner.loadDSL(cl) }

        binding.today = today;
        binding.tomorrow = tomorrow;

        GroovyShell shell = new GroovyShell(binding)
        shell.evaluate(dsl)
        assert binding.variables.x == assertion

    }

    static void main(String[] args) {
        eval("x = from today to tomorrow", (today..tomorrow))
        eval("x = difference(from(today).to(tomorrow))", 2)
        eval("x = difference from today to tomorrow ", 2)

    }

}

这是完全例外:

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: from for class: Script1
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
    at Script1$_run_closure1.doCall(Script1.groovy:3)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at Script1$_run_closure1.doCall(Script1.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at SimpleTest.loadDSL(SimpleTest.groovy:17)
    at SimpleTest$loadDSL.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at SimpleTest$loadDSL.call(Unknown Source)
    at SimpleTest$_eval_closure2.doCall(SimpleTest.groovy:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1099)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1055)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at Script1.run(Script1.groovy:2)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:580)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrap.invoke(PogoMetaMethodSite.java:247)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at SimpleTest.eval(SimpleTest.groovy:54)
    at SimpleTest$eval.callStatic(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:50)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:157)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:169)
    at SimpleTest.main(SimpleTest.groovy:62)

2 个答案:

答案 0 :(得分:1)

如果您在返回范围内添加getDifference方法,则可以在表达式的末尾调用difference,但除此之外,groovy不会解析difference from start to end作为difference(from(start).to(end)),而不是difference(from).start(to).end

    def toMethod = { date ->
        [to: { timeThing ->
            if (timeThing instanceof Date) {
                use(groovy.time.TimeCategory) {
                    def range = date..timeThing
                    range.metaClass.getDifference = { difference delegate } 
                    return range
                }
            }
        }]
    }

你的测试中有一点变化:

    static void main(String[] args) {
        eval("x = from today to tomorrow", (today..tomorrow))
        eval("x = difference(from(today).to(tomorrow))", 2)
        eval("x = from today to tomorrow difference", 2)

    }

两年半后来为时已晚?

答案 1 :(得分:0)

使用命名参数:difference from: today, to: tomorrow

def difference(args){
    Math.abs(args.from - args.to)
}

详细了解Groovy邮件列表讨论[groovy-user]:groovy Command Expression howto do nested expression?