SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

JRubyチュートリアル

JRubyでJavaとRubyを融合する


Rubyスクリプト実行の流れ

 Java内からRubyスクリプトを呼び出す処理について簡単にまとめておきましょう。まず、Rubyのランタイム環境を管理するRubyクラスのインスタンスを用意しておきます。これは以下のようにして取得します。

Ruby ruby = Ruby.getDefaultInstance();

 Rubyの実行に関する機能は、このRubyインスタンスの中に用意されています。続いて、Rubyのスクリプトファイルからスクリプトを読み込むためのFileReaderを用意します。

FileReader reader = new FileReader("test.rb");

 これで準備は完了です。RubyインスタンスのevalScriptを呼び出し、FileReaderを渡せば、そこからスクリプトを読み込んで実行できます。

IRubyObject obj = ruby.evalScript(reader, "");

 実行後の結果は、IRubyObjectというオブジェクトとして返されます。ここでは、スクリプト側でただのStringが返されるようになっていましたので、そのままSystem.out.printlnしています。

 また、ここではevalScriptにFileReaderを渡していますが、実をいえば引数にStringを渡すこともできます。つまり、ファイルからスクリプトを読み込むのでなく、実行するテキストをそのまま渡して実行させることもできるのです。これはなかなか便利ですので覚えておきたいものです。

Rubyクラスを利用する

 Rubyもオブジェクト指向言語ですから、クラスを定義し利用します。では、単純にスクリプトを実行するだけでなく、Rubyのスクリプトに定義されたクラスをJava内から利用することはできるのでしょうか。

 これも実際にやってみましょう。先ほどの「test.rb」のスクリプトを、クラスの形に修正してみます。

require 'java'

class MyDateTime
    include_class 'java.util.GregorianCalendar'
    
    def getDateTime
        cal = GregorianCalendar.new
        date = cal.getTime
        date.toString
    end
end

 続いて、「RuybSample.java」のソースコードを修正し、「test.rb」を読み込んだ後、MyDateTimeクラスのインスタンスを作成してgetDateTimeメソッドを呼び出してみましょう。

package jp.codezine;

import java.io.*;
import org.jruby.*;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class RubySample {

    public static void main(String[] args) {
        Ruby ruby = Ruby.getDefaultInstance();
        ThreadContext context = ruby.getCurrentContext();
        
        try {
            FileReader reader = new FileReader("test.rb");
            ruby.evalScript(reader, "");

            RubyClass rclass = ruby.getClass("MyDateTime");
            IRubyObject robj = rclass.callMethod(context,"new");
            IRubyObject obj = robj.callMethod(context,"getDateTime");
            System.out.println("Result: " + obj);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

 ここではevalScriptでスクリプトを読み込み実行した後、スクリプト内のクラスを利用しています。まず、RubyインスタンスのgetClassを使い、RubyClassを取得します。

RubyClass rclass = ruby.getClass("MyDateTime");

 このRubyClassが、文字通りRubyのクラスを示すものとなります。続いて、このクラスからインスタンスを作成します。

IRubyObject robj = rclass.callMethod(context,"new");

 callMethodは、RubyClassのメソッドを呼び出すためのものです。これは、ThreadContextというクラスのインスタンスと、呼び出すメソッド名のStringを引数にして渡します。ThreadContextは、mainの最初の方でRubyインスタンスのgetCurrentContextを呼び出して取得してあるのが分かるかと思います。

IRubyObject obj = robj.callMethod(context,"getDateTime");

 こうしてインスタンスが作成できたら、callMethodgetDateTimeメソッドを呼び出します。返値は、evalScriptと同様にIRubyObjectインスタンスとして得られます。

引数を持つメソッドの呼び出し

 このgetDateTimeは引数を持たないメソッドでしたので、単にメソッド名を指定するだけで呼び出すことができました。では、引数を持ったメソッドを呼び出す場合はどのようにすればよいのでしょうか。先ほどのMyDateTimeクラスを修正してみましょう。

require 'java'

class MyDateTime
    include_class 'java.util.GregorianCalendar'
    include_class 'java.text.SimpleDateFormat'
    
    def getDateTime str1
        cal = GregorianCalendar.new
        fm = SimpleDateFormat.new
        fm.applyPattern str1
        date = cal.getTime
        fm.format date
    end
end

 getDateTimeに日付フォーマットのためのパターンを引数にして渡すと、それを使ってSimpleDateFormatでフォーマットされた日付表記のStringを返すようにしました。では、RubySampleクラスのmainメソッドを修正して、この修正getDateTimeを呼び出すようにしてみましょう。

public static void main(String[] args) {
    Ruby ruby = Ruby.getDefaultInstance();
    ThreadContext context = ruby.getCurrentContext();
    
    try {
        FileReader reader = new FileReader("test.rb");
        ruby.evalScript(reader, "");

        RubyClass rclass = ruby.getClass("MyDateTime");
        IRubyObject robj = rclass.callMethod(context,"new");
        IRubyObject[] objarr
          = new IRubyObject[]{ruby.newString("yyyy/MM/dd")};
        IRubyObject obj = robj.callMethod(context,"getDateTime",objarr);
        System.out.println("Result: " + obj);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

 引数付きメソッドの場合には、引数をIRubyObject配列として用意し、これをcallMethodに渡します。このIRubyObjectはインターフェースですので、これを実装したクラスのインスタンスであれば設定できます。ここでは、RubyクラスのnewStringというものをつかい、RubyStringインスタンスを作成して設定しています。テキストの値を渡す場合は、大抵これでOKです。Rubyクラスには、Rubyで扱われるさまざまな値を生成するメソッドが用意されているので、これらを使ってオブジェクトを生成して配列に収めていけばいいでしょう。

 こうして作成されたIRubyObject配列が、呼び出したメソッドに引数として渡され、配列のそれぞれのオブジェクトの値がメソッドで利用できるようになる、というわけです。引数がない場合に比べるとやや煩雑ですが、配列の準備方法さえ理解できればそう難しいものではありません。

まとめ

 今回は、JRubyのインストール、Eclipse 3.3での利用、RubyからJavaのクラスライブラリを利用する方法、JavaからRubyのスクリプトやクラスを利用する方法まで、一通りをまとめて説明しました。JRubyのさわり程度ですが、これがどういう使い方ができるのか、イメージぐらいはつかめたのではないでしょうか。

 JRubyは、Java環境上で動くスクリプト言語の中でも非常に重要なものの1つでしょう。RubyはJavaと同じオブジェクト指向言語とはいえ、かなりJavaとは違った形をしています。Javaは、作成する処理が決まれば、誰が書いても大体できあがるソースコードは同じようなものになりますが、Rubyはさまざまな表現が可能です。Javaプログラマにとっては、Rubyに触れることは非常に大きな刺激となるはずです。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1647 2007/12/13 16:08

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー