Выполнить скрипт Groovy на Java с определенным корневым объектом

Я пишу небольшой Groovy DSL, чтобы позволить конечным пользователям определять файлы конфигурации. Идея состоит в том, что я загружаю эти файлы в среду Java, устанавливаю некоторые значения и выполняю их. Вот небольшой пример из DSL до сих пор (стиль Gradle-ish специально):

model {
   file "some/path/here"
   conformsTo "some/other/path/here" 
}

model {
   ...
}

Если я сохраню приведенный выше код в файл (example.groovy), я смогу интегрировать его с Java через GroovyShell:

Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);

Object value = shell.evaluate(...);

Сложная часть - это установка "корневого" объекта. Я знаю, что могу использовать Bindings для установки и вывода переменных. Однако я хочу, чтобы блоки «модели» в DSL были сопоставлены с вызовом метода, т. Е. Я хочу указать эквивалент «этого» для всего скрипта. Все, что я пишу в 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 могут быть лучшие варианты. Я просто не знаю, что искать. Может кто-то указать мне верное направление?


person WeSt    schedule 19.11.2014    source источник


Ответы (2)


Если это обычный 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 = ...;
person Peter Niederwieser    schedule 19.11.2014
comment
Просто из любопытства, так ли это делает Gradle? - person WeSt; 20.11.2014
comment
Gradle имеет собственный базовый класс сценариев и самостоятельно компилирует/запускает сценарии (не через GroovyShell). - person Peter Niederwieser; 20.11.2014

В 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"

Надеюсь, это то, что вы ищете.

person dr.bapbap    schedule 19.11.2014
comment
Поскольку мне нужны циклы и условия if в моем DSL, я не знаю, смогу ли я использовать ConfigSluper, но я попробую. Спасибо за подсказку! - person WeSt; 20.11.2014
comment
я думаю, что OP хочет иметь DSL, а не хранилище для vars, например, slurper более или менее - person cfrick; 20.11.2014