JavaからRuby呼び出し
JRuby上でJavaのクラスを扱う話は良く載ってるんだけど、
Javaの中でRubyのコードを動かしたい。って話がなかなか載ってなかった。
で、色々躓いたのでメモ。
org.jruby.Ruby のインスタンスの evalScriptlet(String ruby_script) メソッドを呼ぶ。
import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; class Hoge { public static void main(String[] args){ Ruby ruby = JavaEmbedUtils.initialize(); try{ ruby.evalScriptlet("arr = %w(a b c)"); ruby.evalScriptlet("arr.each{|str| puts str"); }catch(Exception e){ e.printStackTrace(); }finaly{ JavaEmbedUtils.tarminate(ruby) } } }
こんな感じ。
うまく動かない場合は、CLASSPATHにjruby.jarが入っているか確認。
で、ここまではすんなりできたものの、reqire 'rubygems'でコケる。
ロードパス上にrubygemsが見つからない。的なエラーが。
で、以下のようなコードで回避。
(コードの内容は、Mechanizeでgoogle.comのページを拾ってきて標準出力)
import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; import java.util.List; import java.util.ArrayList; public class TestEvalRubyScript{ public static void main(String[] args){ ListloadPaths = new ArrayList (); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/site_ruby/1.8"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/1.8"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/mechanize-0.7.8/lib"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib"); // loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/mechanize-0.7.8/lib"); Ruby ruby = JavaEmbedUtils.initialize(loadPaths); try{ ruby.evalScriptlet("require '/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib/universal-java1.5/hpricot_scan.jar'"); ruby.evalScriptlet("require '/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib/universal-java1.5/fast_xs.jar'"); ruby.evalScriptlet("require 'rubygems'"); ruby.evalScriptlet("require 'mechanize'"); ruby.evalScriptlet("agent = WWW::Mechanize.new"); ruby.evalScriptlet("page = agent.get('http://www.google.co.jp/')"); ruby.evalScriptlet("puts page.body"); }catch (Exception e){ e.printStackTrace(); }finally{ JavaEmbedUtils.terminate(ruby); } } }
initializeするときにパスを追加する。
jarファイルはruby上で読み込んでもOK。
もっとスマートに書く方法があると思うんだけど。。。とりあえずコレで。
- 追記
さらに、上記のコードではputs を使って表示してた部分を、
Javaで結果を受け取ってJavaのSystem.out.printlnで表示するようにしてみた。
import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; import org.jruby.runtime.builtin.IRubyObject; import java.util.List; import java.util.ArrayList; public class TestEvalRubyScript{ public static void main(String[] args){ ListloadPaths = new ArrayList (); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/site_ruby/1.8"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/1.8"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/mechanize-0.7.8/lib"); loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib"); // loadPaths.add("/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/mechanize-0.7.8/lib"); Ruby ruby = JavaEmbedUtils.initialize(loadPaths); IRubyObject robj = null; try{ robj = ruby.evalScriptlet("require '/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib/universal-java1.5/hpricot_scan.jar'\n"+ "require '/usr/local/jruby-1.1.3/lib/ruby/gems/1.8/gems/hpricot-0.6.161-java/lib/universal-java1.5/fast_xs.jar'\n"+ "require 'rubygems'\n"+ "require 'mechanize'\n"+ "def get_google_page(page_str)\n"+ "agent = WWW::Mechanize.new\n"+ "page = agent.get('http://www.google.co.jp/')\n"+ "page_str << page.body\n"+ "end"); IRubyObject param = JavaEmbedUtils.javaToRuby(ruby, ""); robj.callMethod(ruby.getCurrentContext(), "get_google_page",param); String result = (String)JavaEmbedUtils.rubyToJava(ruby, param, String.class); System.out.println(param); }catch (Exception e){ e.printStackTrace(); }finally{ JavaEmbedUtils.terminate(ruby); } } } class PageBean{ String page = null; public String getPage(){ return page; } public void setPage(String page_str){ page = page_str; } }