Как я могу убедить GroovyShell поддерживать состояние при вызовах eval()?

StackOverflow https://stackoverflow.com/questions/45582

Вопрос

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

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

Это было полезно?

Решение 2

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

Другие советы

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

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...

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

Возможно, это то, что вы ищете?

От Крути в действии

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 позволит вам поддерживать состояние?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top