2008-09-05 7 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 

からのバインディングの適切な使用は、あなたが状態を維持できるようになりますか?

+0

私はそれを見ています:どのように "f"が変数としてバインディングに入りますか?私はそれを見ていない。 – djangofan

2

私はあなたが試用版との間に存在しませ宣言されたクラスについて何を意味するかわからないです次々とevaled際に予想されるように、以下の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... 

あなたが気づいている最後の警告があります。静的型付き変数は、バインディングに格納されていないため、エバールの間に保持されません。したがって、前のスクリプトでは、変数 'klass'はスクリプト呼び出しの間に保持されず、消えます。これを修正するには、すべての変数の最初の使用時にタイプ宣言を削除するだけです。つまり、バインディングに読み書きされます。

関連する問題