1

背景:

我在我的产品的 Eclipse 插件中使用 JRuby。我有一堆定义 DSL 并为我执行操作的脚本。我希望能够在需要时动态地重新加载这些脚本。脚本可以在文件系统上改变自己,而且脚本的位置也可以改变。我什至可以在稍微修改/更改的脚本的文件系统上有多个副本。每次我想要使用来自特定位置的脚本时。

到目前为止,据我所知,使用“load”而不是“require”应该可以完成这项工作。所以现在如果在调用任何 Ruby 方法/函数之前我使用“load 'XXX.rb'”,它将利用新的更改重新加载 XXX.rb。

问题:

在我的代码中,我使用 ScriptingContainer 运行脚本来访问 ruby​​ 函数。我在这个脚本容器上设置了加载路径,以指示应该从哪些位置加载脚本。然而,问题是在随后的调用中,甚至在使用不同的 ScriptingContainer 实例时,我注意到第一次加载的脚本每次都会被使用。“加载”会重新加载它们,但是在加载这些脚本一次之后,下一次我可能需要从不同的位置加载类似的脚本,但它没有发生。

我的假设是,使用不同的脚本容器实例应该已经完成​​了这项工作,但似乎加载路径是全局设置的,并且在新的 ScriptingContainer 实例上调用“setLoadPath”要么不会修改现有路径,要么只会追加。如果后一种情况为真,那么在搜索脚本时,它们可能总是在最旧的路径集上找到,而较新的加载路径会被忽略。

有任何想法吗???

4

1 回答 1

1

解决方案是在创建 ScriptingContainer 实例时为其指定范围。ScriptingContainer 构造函数之一接受 LocalContextScope 类型的参数,使用其中一个常量来定义范围。请参阅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 回答