从JRuby中的不同位置重新加载rb脚本

时间:2012-09-27 13:51:23

标签: ruby jruby

背景:

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

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

问题:

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

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

任何想法???

1 个答案:

答案 0 :(得分: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”:

./脚本/一个/ test.rb

def testCall
  "Called one"
end

./脚本/ 2 / test.rb

def testCall
  "Called two"
end