JavaからRuby呼び出し

JRuby上でJavaのクラスを扱う話は良く載ってるんだけど、

Javaの中でRubyのコードを動かしたい。って話がなかなか載ってなかった。

で、色々躓いたのでメモ。


まず、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)
    }
  }
}

こんな感じ。

うまく動かない場合は、CLASSPATHjruby.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){
        List loadPaths = 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){
        List loadPaths = 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;
    }
}