2012-09-27 37 views
1

背景:從JRuby的不同位置重新加載rb腳本

我在我的產品的eclipse插件中使用JRuby。我有一堆定義DSL併爲我執行操作的腳本。我希望能夠在需要時動態地重新加載這些腳本。腳本可以在文件系統上自行更改,而且腳本的位置也可以更改。我甚至可以在稍微修改/更改腳本的文件系統上擁有多個副本。每次我想要使用特定位置的腳本時。

據我瞭解,到目前爲止,使用「負載」而不是「要求」應該做的工作。因此,現在如果在調用任何Ruby方法/函數之前使用「load'XXX.rb'」,它將使用新的更改重新加載XXX.rb。

問題:

在我的代碼我使用ScriptingContainer運行scriplets訪問紅寶石功能。我在這個腳本容器上設置了加載路徑,以指示腳本應該從哪個位置加載。然而問題在於,在隨後的調用中,甚至是ScriptingContainer的不同實例,我都注意到每次都使用第一次加載的腳本。 「load」會重新加載它們,但是在加載完這些腳本之後,下次我可能需要從不同的位置加載類似的腳本,但它不會發生。

我的假設是利用不同的腳本容器實例應該完成這項工作,但似乎加載路徑是全局設置的,並且在新的ScriptingContainer實例上調用「setLoadPath」或者不修改現有路徑或僅附加。如果後一種情況是真的,那麼可能在搜索腳本時,它們總是在最舊的路徑集中找到,而較新的加載路徑會被忽略。

任何想法???

回答

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/一個/ test.rb

def testCall 
    "Called one" 
end 

./scripts/two/test.rb

def testCall 
    "Called two" 
end