3

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

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

4

3 に答える 3

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 つ注意事項があります。静的に型付けされた変数は、バインディングに格納されないため、eval 間で保持されません。したがって、前のスクリプトでは、変数「klass」はスクリプトの呼び出し間で保持されず、消えます。それを修正するには、すべての変数を最初に使用するときに型宣言を削除するだけです。つまり、それらはバインディングに対して読み取られ、書き込まれます。

于 2008-09-15T15:42:13.430 に答える
1

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

于 2009-09-04T17:08:35.407 に答える
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

バインディングを適切に使用すると、状態を維持できますか?

于 2008-09-05T15:55:37.663 に答える