2007年6月22日 星期五

在 Java 中使用 JRuby & Gems

此篇文章鎖定的目標是,想在 Java 中,使用強大的 Ruby 語法,以及其他 Gems

換句話說,就是拿 Java 當飯吃,卻又想要偷吃 Ruby 的工程師們~囧



http://www.headius.com/jrubywiki/index.php/Java_Integration
JRuby wiki 中提到,要在 java 中使用 gems 需要注意兩件事。

1. jruby.base, jruby.home, jruby.lib, jruby.shell, and jruby.script. You can look in jruby.bat

wiki 中是這麼說,但是我並沒這麼做。我只做了底下這件事。

Ruby runtime = Ruby.getDefaultInstance();

runtime.setJRubyHome(JRUBY_HOME); // 需先設定好 JRUBY_HOME 環境變數

2. 這個就必須要乖乖照做,就是先觀察 jirb 底下 $: load path

["D:/JRuby/jruby-bin-1.0/jruby-1.0/lib/ruby/site_ruby/1.8",

"D:/JRuby/jruby-bin-1.0/jruby-1.0/lib/ruby/site_ruby",

"D:/JRuby/jruby-bin-1.0/jruby-1.0/lib/ruby/1.8",

"D:/JRuby/jruby-bin-1.0/jruby-1.0/lib/ruby/1.8/java",

"lib/ruby/1.8",

"."]

乖乖做吧

runtime.evalScript("$: << '" + JRUBY_HOME + "/lib/ruby/site_ruby/1.8'");

runtime.evalScript("$: << '" + JRUBY_HOME + "/lib/ruby/site_ruby'");

runtime.evalScript("$: << '" + JRUBY_HOME + "/lib/ruby/1.8'");

runtime.evalScript("$: << '" + JRUBY_HOME + "/lib/ruby/1.8/java'");

runtime.evalScript("$: << 'lib/ruby/1.8'");

以上狀況,皆為理想情況下,就能在 java 中使用 gems

但是,都沒提到,windows 需要注意的問題。


Windows 使用者,另外需要注意,目錄分隔符號。

問題出在底下程式碼 ( rubygems.rb )

# gem directories must come after -I and ENV['RUBYLIB']

$:.insert($:.index(sitelibdir), *require_paths)

稍微解釋一下

問題出在 $:.index(sitelibdir)

sitelibdir sitelibdir = Config::CONFIG['sitelibdir']

是從 require ‘rubygems’ require ‘rbconfig’ 定義好的

$jruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']"
D:/JRuby/jruby-bin-1.0/jruby-1.0/lib/ruby/site_ruby/1.8


因為通常我們設定 windows 的環境變數,目錄分隔符號通常都是使用左上右下 => \

但是 rbconfig 所用的是 右上左下 => /

所以我們在定義 load path 之前,需要先把目錄分隔符號轉成 右上左下 => /


String JRUBY_HOME = System.getenv().get("JRUBY_HOME").replaceAll("\\\\", "/");


接下來安裝 台中邪惡 Ruby 最常用的 gem – hpricot

因為 ruby 許多東西為了增加效能或其他目的,某些部份可能會使用 C code

hpricot 也是如此,所以 hpricot 作者有改寫一個 JRuby 版本

參考 Ola Bini Hpricot goodness

$jruby bin/gem install hpricot --source http://code.whytheluckystiff.net

然後在 Java 中測試

runtime.evalScript("require 'rubygems'");

runtime.evalScript("require 'hpricot'");

runtime.evalScript("doc = Hpricot(open(\"http://redhanded.hobix.com/index.html\"))");

runtime.evalScript("puts doc");

或是跳過那難用的 Java Regexp

使用 Ruby Regexp

RubyString str = (RubyString) runtime.evalScript("$1 if 'a1b2c3' =~ /(\\d)/");

System.out.println(str.toString() + " = str");



以上程式碼,聰明的你應該想到該怎麼使用 Ruby 去載入 .rb 吧!

才不會像上面那麼難閱讀。


還有 過一陣子再來討論一下,為何不把 .rb 包成 jar 檔使用。

沒有留言: