groovy命令表达式如何做嵌套表达式?
问题描述:
我正在用Groovy开发一个不错的小DSL。groovy命令表达式如何做嵌套表达式?
我真的很喜欢高阶函数的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))
我总是得到错误:
No such property: from for class: Script1.
下面是测试类主要方法。第三个断言失败:
任何人都可以告诉我一个例子如何做到这一点?
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)
答
使用命名参数:difference from: today, to: tomorrow
def difference(args){ Math.abs(args.from - args.to) }
查看更多关于Groovy邮件列表讨论[常规用户]:groovy Command Expression howto do nested expression?
答
如果您添加一个getDifference
方法返回范围内,你可以在你的表达的末尾调用difference
,但除此之外,常规不会解析difference from start to end
为difference(from(start).to(end))
,而是difference(from).start(to).end
和一个小变化,你的测试:
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)
}
两年半来晚了?
大声笑,这是从一个时间,当我认为DSL可以完全人类可读的任何人。但是我错了。 – 2014-10-13 06:51:27
这不会对我有用,因为“单词序列”必须像英语一样...... – 2014-10-13 07:59:38
我想你会需要去为你自己的antlr。但即使如此,你可能正在寻找[自然语言解析器](http://nlp.stanford.edu/software/lex-parser.shtml) – Will 2014-10-13 12:59:48