1

バックグラウンド:

製品の Eclipse プラグインで JRuby を使用しています。DSL を定義して操作を実行するスクリプトがたくさんあります。必要に応じて、これらのスクリプトを動的に再読み込みできるようにしたいと考えています。スクリプトはファイル システム上で変更される可能性があり、さらにスクリプトの場所も変更される可能性があります。わずかに変更/変更されたスクリプトの複数のコピーをファイル システムに作成することもできます。特定の場所のスクリプトを利用するたびに。

これまでに理解したように、「require」の代わりに「load」を使用するとうまくいくはずです。したがって、Ruby のメソッド/関数を呼び出す前に「load 'XXX.rb'」を使用すると、新しい変更を利用して XXX.rb がリロードされます。

問題:

私のコードでは、ScriptingContainer を使用してスクリプトレットを実行し、Ruby 関数にアクセスしています。このスクリプト コンテナにロード パスを設定して、スクリプトをロードする場所を示します。ただし、問題は、その後の呼び出しで、ScriptingContainer のインスタンスが異なる場合でも、最初に読み込まれたスクリプトが毎回使用されることに気付きました。「ロード」はそれらをリロードしますが、それらのスクリプトを一度ロードした後、次回は別の場所から同様のスクリプトをロードする必要があるかもしれませんが、それは起こりません。

私の仮定では、別のスクリプト コンテナー インスタンスを利用すればうまくいくはずでしたが、ロード パスはどこかにグローバルに設定されており、新しい ScriptingContainer インスタンスで「setLoadPath」を呼び出しても、既存のパスが変更されないか、追加されるだけのようです。後者の場合は、おそらくスクリプトを検索すると、スクリプトは常に最も古いパス セットで検出され、新しいロード パスは無視されます。

何か案は???

4

1 に答える 1

1

解決策は、作成時に ScriptingContainer インスタンスのスコープを指定することです。ScriptingContainer コンストラクターの 1 つは LocalContextScope 型のパラメーターを受け取り、定数の 1 つを使用してスコープを定義します。LocalContextScope.javaを参照してください。

この欠陥と解決策をテストするために、小さなスニペットを書きました。あなたはそれを試すことができます:

public class LoadPathProblem {

  public static void main(String[] args) {
    // Create the first container
    ScriptingContainer c1 = new ScriptingContainer();
    // FIX ScriptingContainer c1 = new ScriptingContainer(LocalContextScope.SINGLETHREAD);

    // Setting a load path for scripts
    String path1[] = new String[] { ".\\scripts\\one" };
    c1.getProvider().setLoadPaths(Arrays.asList(path1));

    // Run a script that requires loading scripts in the load path above
    EvalUnit unit1 = c1.parse("load 'test.rb'\n" + "testCall");
    IRubyObject ret1 = unit1.run();
    System.out.println(JavaEmbedUtils.rubyToJava(ret1));

    // Create the second container, completely independent of the first one
    ScriptingContainer c2 = new ScriptingContainer();
    // FIX ScriptingContainer c2 = new ScriptingContainer(LocalContextScope.SINGLETHREAD);

    // Setting a different load path for this container as compared to the first container
    String path2[] = new String[] { ".\\Scripts\\two" };
    c2.getProvider().setLoadPaths(Arrays.asList(path2));

    // Run a script that requires loading scripts in the different path
    EvalUnit unit2 = c2.parse("load 'test.rb'\n" + "testCall");
    IRubyObject ret2 = unit2.run();

    /*
     * PROBLEM: Expected here that the function testCall will be called from
     * the .\scripts\two\test.rb, but as you can see the output says that
     * the function was still called from .\scripts\one\test.rb.
     */
    System.out.println(JavaEmbedUtils.rubyToJava(ret2));
  }
}

上記のコードを試すためのテスト スクリプトは、別のフォルダーに配置できますが、同じファイル名 (上記の例では "test.rb") を使用できます。

./scripts/one/test.rb

def testCall
  "Called one"
end

./scripts/two/test.rb

def testCall
  "Called two"
end
于 2012-10-24T08:47:35.730 に答える