我正在编写一个小Groovy DSL
,让最终用户定义配置文件。这个想法是我在 Java 环境中加载这些文件,设置一些值并执行它们。这是到目前为止DSL的一个小例子(Gradle风格的是故意的):
model {
file "some/path/here"
conformsTo "some/other/path/here"
}
model {
...
}
如果我将上面的代码保存到一个文件(example.groovy),我可以通过GroovyShell
将其与Java集成:
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Object value = shell.evaluate(...);
棘手的部分是设置"根"对象。我知道我可以使用绑定来设置输入和输出变量。但是,我希望DSL中的"模型"块映射到方法调用,即我想为整个脚本指定一个"this"等效项。我在DSL中编写的任何内容都应该在这个"根"对象的范围内,例如
// model is a method of the root object
model {
file "some/path/here"
conformsTo someValue // if someValue is not defined inside the script, I want it to be considered as a property of the root object
}
我找到了这篇关于我想要实现的目标的优秀文章,但由于它是从 2008 年开始的,我认为在较新的 Groovy 版本中可能有更好的选择。我只是不知道该寻找什么。谁能指出我正确的方向?
如果这是普通的Groovy(不是Gradle),那么groovy.util.DelegatingScript
就是你要找的。查看其Javadoc以了解详细信息。
委派脚本是将自定义DSL加载为脚本然后执行它的便捷基础。以下示例代码演示了如何执行此操作:
class MyDSL { public void foo(int x, int y, Closure z) { ... } public void setBar(String a) { ... } } CompilerConfiguration cc = new CompilerConfiguration(); cc.setScriptBaseClass(DelegatingScript.class); GroovyShell sh = new GroovyShell(cl,new Binding(),cc); DelegatingScript script = (DelegatingScript)sh.parse(new File("my.dsl")) script.setDelegate(new MyDSL()); script.run();
my.dsl 可以看起来像这样:
foo(1,2) { .... } bar = ...;
Groovy中有一个简单的解决方案可以将配置保留在属性中,它是一个ConfigSlurper。看看 ConfigSlurper
sample {
foo = "default_foo"
bar = "default_bar"
}
environments {
development {
sample {
foo = "dev_foo"
}
}
test {
sample {
bar = "test_bar"
}
}
}
def config = new ConfigSlurper("development").parse(new File('Sample.groovy').toURL())
assert config.sample.foo == "dev_foo"
assert config.sample.bar == "default_bar"
config = new ConfigSlurper("test").parse(new File('Sample.groovy').toURL())
assert config.sample.foo == "default_foo"
assert config.sample.bar == "test_bar"
希望这就是你要找的。