2008-09-05 2 views
3

Я пытаюсь использовать Groovy для создания интерактивного режима сценариев/макросов для моего приложения. Приложение OSGi, и большая часть информации, которая может понадобиться сценариям, не знает заранее. Я предположил, что могу использовать GroovyShell и вызывать eval() несколько раз, постоянно добавляя к пространству имен, когда загружаются пакеты OSGi. GroovyShell поддерживает переменное состояние по нескольким eval-вызовам, но не к определениям классов или методам.Как я могу убедить GroovyShell поддерживать состояние над вызовами eval()?

Цель: создать базовый класс во время запуска. Когда OSGi связывает нагрузку, создайте производные классы по мере необходимости.

ответ

1

Законченный код для инъекций перед каждой компиляцией скрипта. Конечная цель заключается в том, что написанный пользователем скрипт имеет доступный для использования язык.

0

Это может быть то, что вы ищете?

От Groovy in Action

def binding = new Binding(x: 6, y: 4) 
def shell = new GroovyShell(binding) 
def expression = '''f = x * y''' 
shell.evaluate(expression) 
assert binding.getVariable("f") == 24 

Соответствующее использование Binding позволит поддерживать состояние?

+0

im глядя на это: как «f» попадает в привязку как переменную? им не видя этого. – djangofan 2011-06-18 20:28:12

2

Я не уверен, что вы имеете в виду об объявленных классов не существующих между Evals, следующие два сценария работы, как ожидается, когда evaled один за другим:

class C {{println 'hi'}} 
new C() 

...

new C() 

Однако методы становятся связанными с классом, который их объявил, а GroovyShell создает новый класс для каждого экземпляра. Если вам не требуется возвращаемое значение любого из скриптов, и они действительно являются сценариями (а не классами с основными методами), вы можете присоединить следующее к концу каждого оцениваемого скрипта.

Class klass = this.getClass() 
this.getMetaClass().getMethods().each { 
    if (it.declaringClass.cachedClass == klass) { 
    binding[it.name] = this.&"$it.name" 
    } 
} 

Если вы зависите от возвращаемого значения вы можете вручную управлять оценками и запустить скрипт как часть вашего разбора (предупреждение, непроверенный код следует, только в иллюстративных целях) ...

String scriptText = ... 
Script script = shell.parse(scriptText) 
def returnValue = script.run() 
Class klass = script.getClass() 
script.getMetaClass().getMethods().each { 
    if (it.declaringClass.cachedClass == klass) { 
    shell.context[it.name] = this.&"$it.name" 
    } 
} 
// do whatever with returnValue... 

Существует одно последнее предупреждение, о котором я уверен, что вы знаете. Статически типизированные переменные не сохраняются между оценками, поскольку они не сохраняются в привязке. Поэтому в предыдущем сценарии переменная 'klass' не будет храниться между вызовами сценария и исчезнет. Чтобы исправить это, просто удалите объявления типа при первом использовании всех переменных, это означает, что они будут прочитаны и записаны в привязку.

Смежные вопросы