实际上,我正在尝试用groovy编写DSL。到目前为止......
关于授权和拦截不需要的(Closure)结构,有些事情不清楚:
首先:如何抛出(类型?)异常以指向DSL中失败的正确代码行?
假设
abstract MyScript extends Script {
def type(@DelegateTo(MyType) Closure cl) {
cl.delegate = new MyType()
cl()
this
}
}
下
new GroovyShell(this.class.classLoader, new CompilerConfiguration(scriptBaseClass: MyScript.name)).evaluate(…)
传递的DSL /闭包
type {
foo: "bar"
}
默默地传递。
我知道,foo:
只是一个POJ标签,但我不确定Closure的定义是什么?
我没有找到任何有关AST元编程的内容,以便与任何已定义的标签联系使用它们吗?
给予
type {
foo = "bar"
}
很明显,他会尝试设置属性foo,但是我真的必须通过拦截不需要的字段/道具
class MyType {
def propertyMissing(String name) {
… // where I'm unable to println name since this leads to field access 'name' ...
}
}
虽然仍允许用户传递
type {
foo "bar"
}
导致方法未定义..所以我必须另外写一些metaClass.methodMissing或metaClass.invokeMethod东西..
同时我倾向于忽略我的dsl中的任何闭包只使用简单的
def type(Map vars) {
store << new MyType(vars)
// where in the constructor I was forced to write metaClass stuff to validate that only fields are given in the map that are defined in the class
}
有效,但两种草稿都不是我在阅读时所期望的那样;#groovy非常适合制作DSL&#34; ...
答案 0 :(得分:0)
我会尝试不同的选项,然后选择一个。
为了引导您的用户,您应该提供类似于常规编译器的反馈(即行号和列,可能是表达式)。
强制输入的正确性可能非常重要 - 取决于您的DSL。
例如:
type {
foo: "bar"
}
只是一个返回String bar
的闭包。这是你的用户应该做的事情吗?该标签将成为org.codehaus.groovy.ast.stmt.Statement.statementLabels
中AST,AFAIK的一部分。如果您希望此语法为foo
分配内容,那么您需要重写AST。 Expression可以成为局部变量foo
的声明,也可以成为Field foo的赋值。但是,Groovy为您提供了一些使创建DSL更容易的功能:
您已使用@DelegateTo(MyType)
,因此您只需将字段foo
添加到MyType
:
class MyType {
String foo
}
然后使用@CompileStatic
或@TypeChecked
验证您的脚本。请注意,@CompileStatic
将停用运行时元编程(即propertyMissing
等等不再被调用。)而@TypeChecked
则不会。但是,这只会验证类型正确性。即:除了声明的字段之外的任何内容都将失败并且分配不兼容的类型将失败。它不会验证是否已将某些内容分配给foo
。如果需要,您可以在调用Closure后验证代理的内容。