使用特定的" Root"在Java中执行Groovy脚本。宾语

时间:2014-11-19 21:43:47

标签: java groovy dsl

我正在编写一个小Groovy DSL来让最终用户定义配置文件。我的想法是我在Java环境中加载这些文件,设置一些值并执行它们。这里是DSL的一个小例子(Gradle-ish风格是故意的):

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(...);

棘手的部分是设置" root"宾语。我知道我可以使用Bindings来设置和输出变量。但是,我想要"模型" DSL中的块被映射到方法调用,即我想指定一个"这个"相当于整个脚本。我在DSL上写的任何东西都应该在这个" root"对象,例如。

// 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
}

我发现了this关于我想要实现的目标的优秀文章,但是从2008年开始,我认为在较新的Groovy版本中可能有更好的选择。我只是不知道该找什么。有人能指出我正确的方向吗?

2 个答案:

答案 0 :(得分:3)

如果这是普通的Groovy(不是Gradle),那么groovy.util.DelegatingScript就是你要找的。查看其Javadoc以获取详细信息。

  

DelegatingScript是将自定义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 = ...;

答案 1 :(得分:1)

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"

希望这就是你要找的东西。