GroovyShell に eval() 呼び出しを通じて状態を維持させるにはどうすればよいでしょうか?

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

質問

Groovy を使用して、アプリケーションの対話型スクリプト/マクロ モードを作成しようとしています。アプリケーションは OSGi であり、スクリプトに必要な情報の多くは事前にはわかりません。GroovyShell を使用して、OSGi バンドルがロードされるときに名前空間に継続的に追加する eval() を複数回呼び出すことができると考えました。GroovyShell は、複数の eval 呼び出しにわたって変数の状態を維持しますが、クラス定義やメソッドは維持しません。

ゴール:起動時に基本クラスを作成します。OSGi バンドルがロードされると、必要に応じて派生クラスを作成します。

役に立ちましたか?

解決 2

各スクリプトのコンパイル前にコードを挿入することになりました。最終目標は、ユーザーが作成したスクリプトでドメイン固有の言語を使用できるようにすることです。

他のヒント

宣言されたクラスが eval 間に存在しないという意味がよくわかりませんが、次の 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...

最後にもう 1 つ注意事項がありますので、皆さんもご存知かと思います。静的に型指定された変数はバインディングに格納されないため、評価間では保持されません。したがって、前のスクリプトでは、変数「klass」はスクリプトの呼び出し間で保持されず、消えてしまいます。これを修正するには、すべての変数の最初の使用時に型宣言を削除するだけです。これは、変数がバインディングに対して読み書きされることを意味します。

これがあなたが探しているものかもしれません?

から グルーヴィーなアクション

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