如何正确从Java调用JRuby中Test模块的Test_1方法?
Java调用Ruby模块方法报错的解决方法
问题场景
尝试从Java调用Ruby模块中的方法,运行后报错提示方法未定义,相关代码及错误信息如下:
Ruby代码文件
test_a.rb
module Test def Test.Test_1 stmt = "Test 1" stmt end end
test.rb(引入test_a.rb)
require_relative "./test/test_a.rb"
Java调用代码
package com.example; import java.util.ArrayList; import org.jruby.embed.LocalContextScope; import org.jruby.embed.LocalVariableBehavior; import org.jruby.embed.PathType; import org.jruby.embed.ScriptingContainer; public class test_ruby { public static void main(String[] args) { try { ScriptingContainer jruby = new ScriptingContainer(LocalContextScope.THREADSAFE, LocalVariableBehavior.GLOBAL); ArrayList<String> loadPath = new ArrayList<>(); loadPath.add("C:\\Users\\nikol\\Downloads\\starter\\ruby\\base"); jruby.setLoadPaths(loadPath); System.out.println("Load Files"); jruby.runScriptlet(PathType.RELATIVE, "ruby\\\\base\\test\\lib\\test.rb"); String returnValue = jruby.runRubyMethod(String.class, null, "Test.Test_1"); System.out.println(returnValue); } catch (Exception e) { e.printStackTrace(); } } }
错误信息
Load Files org.jruby.embed.InvokeFailedException: org.jruby.exceptions.NoMethodError: (NoMethodError) undefined method `Test.Test_1' for nil:NilClass at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.doInvokeMethod(EmbedRubyObjectAdapterImpl.java:251) at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.runRubyMethod(EmbedRubyObjectAdapterImpl.java:198) at org.jruby.embed.ScriptingContainer.runRubyMethod(ScriptingContainer.java:1579) at com.example.test_ruby.main(test_ruby.java:19) Caused by: org.jruby.exceptions.NoMethodError: (NoMethodError) undefined method `Test.Test_1' for nil:NilClass
正确调用方式
错误原因是runRubyMethod不能直接把Test.Test_1作为方法名传入,有两种可行的解决方式:
方式一:获取模块对象后调用方法
先获取Test模块的Ruby对象,再调用其对应的方法:
package com.example; import java.util.ArrayList; import org.jruby.embed.LocalContextScope; import org.jruby.embed.LocalVariableBehavior; import org.jruby.embed.PathType; import org.jruby.embed.ScriptingContainer; public class test_ruby { public static void main(String[] args) { try { ScriptingContainer jruby = new ScriptingContainer(LocalContextScope.THREADSAFE, LocalVariableBehavior.GLOBAL); ArrayList<String> loadPath = new ArrayList<>(); loadPath.add("C:\\Users\\nikol\\Downloads\\starter\\ruby\\base"); jruby.setLoadPaths(loadPath); System.out.println("Load Files"); // 加载Ruby文件 jruby.runScriptlet(PathType.RELATIVE, "ruby\\\\base\\test\\lib\\test.rb"); // 获取Test模块对象 Object testModule = jruby.runScriptlet("Test"); // 调用模块中的Test_1方法 String returnValue = jruby.runRubyMethod(String.class, testModule, "Test_1"); System.out.println(returnValue); } catch (Exception e) { e.printStackTrace(); } } }
方式二:直接执行Ruby调用语句
使用runScriptlet直接执行完整的Ruby方法调用语句,写法更简洁:
package com.example; import java.util.ArrayList; import org.jruby.embed.LocalContextScope; import org.jruby.embed.LocalVariableBehavior; import org.jruby.embed.PathType; import org.jruby.embed.ScriptingContainer; public class test_ruby { public static void main(String[] args) { try { ScriptingContainer jruby = new ScriptingContainer(LocalContextScope.THREADSAFE, LocalVariableBehavior.GLOBAL); ArrayList<String> loadPath = new ArrayList<>(); loadPath.add("C:\\Users\\nikol\\Downloads\\starter\\ruby\\base"); jruby.setLoadPaths(loadPath); System.out.println("Load Files"); jruby.runScriptlet(PathType.RELATIVE, "ruby\\\\base\\test\\lib\\test.rb"); // 直接执行Ruby方法调用 String returnValue = (String) jruby.runScriptlet("Test.Test_1"); System.out.println(returnValue); } catch (Exception e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

