小山博史のJavaを楽しむ(4)

(Java+Derby)* Ruby on Rails プログラミング


ガリレオ
小山博史
2007/2/7


教育界、技術者コミュニティでJava言語の教育と啓蒙に長年携わってきた筆者が、独自の視点からJavaの面白さを掘り下げていく。(編集部)




 Java SE 6のリリースにより、Javaプログラミングにおけるスクリプトの重要性もますます高まってきています。いうまでもありませんが、これからはWebサービスをいかに実現していけるか、ということがビジネスにおいて重要ですから、これを実装する言語として、RubyPythonPHPといったプログラミング言語に興味を持ち始めている開発者も多いのではないでしょうか?

 今回は、そんなJavaプログラマがRubyでプログラミングをするとしたら、どんな環境を用意するのがいいのだろうか、ということで調べてみました。

JRuby on Railsとは何か?

 プログラミング言語Rubyといって最初に注目するのは、なんといってもRailsでしょう。RoR(Ruby on Rails)が世の中に紹介されてから、はやるまではあっという間でした。DRY(Don't Repeat Yourself 繰り返しはやめよう)Convention over Configuration(設定よりも規約)、といった方針で開発を進めることができる、という点が開発者から支持されたのでしょう。このような状況ですから、Rubyをさわってみたい、とJavaプログラマが考えるのも当たり前のことです。

編集部注RoR(Ruby On Rails)についての詳細を知りたい読者は、「Javaから見たRuby on Rails」をご参照願います。

 では、JavaプログラマがいまからRubyを始めるとしたら、どうするのが良いでしょうか。単にRubyを使うだけではつまらないですから、Javaと連携させたいと思うのではないでしょうか。

 検索エンジンで探すとすぐに見つかりますが、世の中にはJavaによるRubyの実装版JRubyというものがあります。JRubyは2006年7月までは、「sourceforge.net」で開発されていましたが、2006年8月からは、「codehaus.org」に移動しています。2006年9月には、JRubyのコア開発者であるCharles Oliver Nutter氏とThomas Enebo氏はSun Microsystemsに勤めることになり、開発コミュニティでは大きなニュースとなりました。

 JRubyは100%純粋なJavaプログラムなので、Javaの実行環境があれば使えます。JRubyのバージョンは0.9.2なので、力不足のように思ってしまうかもしれませんが、Railsに必要なRuby1.8.5と互換性がありますから大丈夫です。何といっても、JavaのクラスをRubyから使える、というのは魅力的です。ライセンスもCPLGPLLGPLの中から選択できます。ということで、最新版のJRubyでRailsを動かしてみることにしました。

JRuby on Railsをインストールするには?

 早速、JRubyのサイトからたどれる「Index of /jruby」へアクセスし、jruby-java5-bin-0.9.2.tar.gzをダウンロードしました。

 今回は、Fedora Core 5へSunのJDK 6をインストールした環境で実行するようにします。筆者のFedora Core 5の場合は、gijがインストールされていたので、確実にJDK6を使うように環境変数を設定しました。ここでは、/usr/java/jdkへJDK6をインストールしたとしています。

編集部注Fedora Core 5でのgijの使い方についての詳細を知りたい読者は、「小山博史のJavaを楽しむ(2)、いろいろなJavaを使ってみよう」の「GNU系のJavaの実装」「gcj、gij、jikesの使い方」をご参照願います。

 JRubyのインストール自体は非常に簡単に終わりました。実際にコマンドを使ってバージョンを確認してみると、JRubyの最新版はRuby 1.8.5互換であることが分かりました。Railsの最新版は1.2で、Ruby 1.8.5が必要なのですが、大丈夫そうです。ここまでは特に問題ありませんでした。

バージョン確認
$ mkdir ~/program; cd ~/program
$ wget http://dist.codehaus.org/jruby/jruby-java5-bin-0.9.2.tar.gz
$ tar xzf jruby-java5-bin-0.9.2.tar.gz
$ export JAVA_HOME=/usr/java/jdk
$ export JRUBY_HOME=~/program/jruby-0.9.2
$ export PATH=$JAVA_HOME/bin:$JRUBY_HOME/bin:$PATH
$ jruby -version
ruby 1.8.5 (0) [java]

 さて、目標とするJRuby on Railsのインストールですが、普通にインストールできるようです。そこで、Railsのサイトにある説明に従って、インストールを進めました。

 インストールに当たっては、RubyのパッケージマネージャであるRubyGemsが必要だということなので、RubyGemsのサイトからrubygems-0.9.0.tgzをダウンロードして展開しました。

 実は、ここで失敗して、最初はrubygems-0.9.1.tgzをダウンロードしてしまいました。筆者の環境では、それを使うと、Railsのインストールができませんでした。ともあれ、RubyGemsのインストールはrubygems-0.9.0.tgzを展開してから、jrubyコマンドでsetup.rbを実行するだけでした。

Railsインストール
$ tar xzf rubygems-0.9.0.tgz; cd rubygems-0.9.0
$ jruby setup.rb

 RubyGemsのようなパッケージマネージャを使うと、いろいろなライブラリのインストールがとても簡単にできます。JCP(Java Community Process)を通じて仕様がコントロールされているJavaでは、あまり必要性がないかもしれませんが、やはり実装の選択肢も増えてきているので、Javaにもパッケージマネージャのようなものが欲しくなってきます。Apache Mavenがパッケージを管理する似たような機能を提供していますから、もしかしてこれが標準になっていくのかもしれません。

編集部注JCPについての詳細を知りたい読者は、「Javaプログラマになるための定番Javaサイトの歩き方」の「これからのJava技術を知るために「JCP(Java Community Process)」」をご参照願います。
編集部注Apache Mavenについての詳細を知りたい読者は、「Java開発支援ツールの定番」の「Maven」をご参照願います。

 RubyGemsのインストールができたので、いよいよRailsのインストールになりましたが、ここで注意が必要です。最初は、これに気が付かなくて結構時間を取られてしまいました。gemの実行をするに当たってはjrubyを明示的に指定して使う必要があるのです。

 なお、ここでは、時間を短縮するために「--no-ri」(RIドキュメントを生成しない)、「--no-rdoc」(RDocドキュメントを生成しない)としています。成功すると、railsだけでなく、rakeactivesupportといった依存関係にあるモジュールもインストールされます。ついでに、後で使うので、activerecord-jdbcもインストールしておきます。

gemの実行
$ jruby $JRUBY_HOME/bin/gem install rails -y --no-ri --no-rdoc

(略)

warning: JRuby does not currently support defining finalizers
Successfully installed rails-1.2.1
Successfully installed rake-0.7.1
Successfully installed activesupport-1.4.0
Successfully installed activerecord-1.15.1
Successfully installed actionpack-1.13.1
Successfully installed actionmailer-1.3.1
Successfully installed actionwebservice-1.2.1
$ jruby $JRUBY_HOME/bin/gem install activerecord-jdbc -y --no-ri --no-rdoc

(略)

Successfully installed ActiveRecord-JDBC-0.2.2

 ちなみに、途中に警告が出ていましたが、取りあえずインストールはできたようです。何度か試したところ、うまくいかないときもあるようです。そんなときは、rakeだけ先にインストールする(上記コマンドのrailsをrakeに変更するだけ)など、1つずつインストールすると大丈夫な場合もありますから、試してみるとよいでしょう。

 さて、実行をするときにもjrubyを使います。Railsのサイトには、「rails path/to/your/new/application」と書いてあるのですが、このとおりに実行すると、筆者の環境では、「require: command not found」などのエラーが出てしまいました。何がいけないのかと、「$JRUBY_HOME/bin/rails」コマンドの中身を見たところ、普通のRubyプログラムでしたから、明示的にjrubyコマンドを指定して実行すればいい、と気が付きました。ここでは、~/workspaceというディレクトリをあらかじめ作成しておいて、そこへsampleappアプリケーションを作成することにしました。

 railsコマンドが成功して、Railsアプリケーションが作成されてから、WEBrickサーバを実行して、http://localhost:3000/へアクセスしました。きちんと初期画面を表示できたので、後は普通にRailsを使うのと同じように開発できるのが分かりました。

Railsの実行
$ mkdir ~/workspace
$ jruby $JRUBY_HOME/bin/rails ~/workspace/sampleapp
$ cd ~/workspace/sampleapp; jruby script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2007-01-29 17:51:03] INFO WEBrick 1.3.1
[2007-01-29 17:51:03] INFO ruby 1.8.5 (0) [java]
[2007-01-29 17:51:03] INFO WEBrick::HTTPServer#start: pid=5947506 port=3000


JRubyでJDBC接続

 せっかくRailsを使うようになっても、データベースが使えないとあまり意味がありません。調べてみると、Railsで使っているActiveRecordモジュールでは、JDBCと連携させる方法がありました。ActiveRecord-JDBCというモジュールを使えばいいようなので、こちらもインストールして使ってみることにしました。

 データベースはせっかくなので、JDK 6に付属するDerbyを使います。「小山博史のJavaを楽しむ(3)、待望のJava SE 6 でパーシステンス」では、組み込みモードで使いましたが、ここではサーバモードで起動して、サーバクライアント方式でDBを利用することにしました。認証も付けておきたいので、設定ファイルを次のように作成してDB用にアカウントとパスワードを設定し、作成するテーブル用のSQL文も用意しておきました。

設定ファイル(~/workspace/sampleapp/db/derby.properties)
derby.connection.requireAuthentication=true
derby.authentication.provider=BUILTIN
derby.user.adminuser=sapass

SQL文ファイル(~/workspace/sampleapp/db/create.sql)
create table users (
    id integer not null generated
        always as identity (start with 1, increment by 1),
    name varchar(255)
);

Derbyをサーバモードで起動
$ export JAVA_HOME=/usr/java/jdk
$ export DERBY_HOME=$JAVA_HOME/db
$ cd ~/workspace/sampleapp/db
$ $DERBY_HOME/frameworks/NetworkServer/bin/startNetworkServer.ksh

 サーバを起動したら、別コンソールを開いて次のようにデータベースを作成して、さらにSQL文ファイルを読み込み実行してテーブルを作成しました。なお、sampledbデータベースが作成されると「~/workspace/hello/db」にsampledbディレクトリが作成されているはずです。MySQLなどをわざわざ用意しなくてもDerbyだけで準備が済むので、手間が全然掛かりません。

別コンソールでテーブル作成
$ $DERBY_HOME/frameworks/NetworkServer/bin/ij.ksh
ij バージョン 10.2
ij> connect 'jdbc:derby://localhost/sampledb;create=true;
user=adminuser;password=sapass';
ij> run 'create.sql';

(略)

ij> quit;
0 行が挿入/更新/削除されました

注意
 なお、Derbyを停止するには、次のようにコンソールからコマンドを入力します。

$ $DERBY_HOME/frameworks/NetworkServer/bin/stopNetworkServer.ksh

 最後に、Railsのデータベース設定を行いました。通常は、ymlファイルだけを編集すればよいのですが、ActiveRecord-JDBCを使うために、環境ファイルも編集が必要です。環境ファイルについては、File.joinの記述がある行の下へjdbc_adapterに関する記述を追加しました。

Railsのデータベース設定(~/workspace/hello/config/database.yml)
development:
adapter: jdbc
driver: org.apache.derby.jdbc.ClientDriver
url: jdbc:derby://localhost:1527/sampledb
username: adminuser
password: sapass

Rails環境ファイル(~/workspace/hello/config/environment.rb)
require File.join(File.dirname(__FILE__), 'boot')
require 'active_record/connection_adapters/jdbc_adapter'

 データベースとRailsの準備が整ったので、いざ、データベースドライバを含むJARファイルをCLASSPATHへ含めながら、scaffold(「足場」と訳されます)の生成を実行してみました。無事に生成ができたので、http://localhost:3000/usersへアクセスしてみると、しっかりとscaffoldで作成された画面が表示されました。

 ここで、sampledbにあるusersテーブルのレコードを新規追加したり、編集したり、削除したりといった簡単な作業ができることを確認しました。本当に簡単に動作させられたので、JRuby on Railsもいろいろと使えそうです。

scaffold生成
$ export CLASSPATH=/usr/java/jdk/db/lib/derbyclient.jar:$CLASSPATH
$ jruby script/generate scaffold user
exists app/controllers/

(略)

identical public/stylesheets/scaffold.css


JRubyとJavaを使って「Hello JRuby」

 ここまでで、JRubyでRailsを動かせることが分かりましたが、やはり、JRubyからJavaのクラスを呼び出す方法も確認しておきたいところです。

 JRubyにはサンプルが同梱されていたので、動作させてみました。見てみると、new演算は「java.io.FileReader.new filename」のように「クラス名.new」と記述して呼び出せますし、メソッドの呼び出しは、「br.readLine」のようにすれば良いようです。Javaのクラスが簡単に利用できるので、JavaプログラマだとRubyのクラスを使わずに、ついついJavaのクラスばかり使ってしまうかもしれません。

サンプルの実行例(JRuby 0.9.2に同梱されているサンプルより引用)
$ cd $JRUBY_HOME
$ jruby samples/java2.rb
------ ./samples/java2.rb------
require "java"

filename = "./samples/java2.rb"
fr = java.io.FileReader.new filename
br = java.io.BufferedReader.new fr

s = br.readLine

(略)

br.close
------ ./samples/java2.rb end ------

 次に、JavaからJRubyのクラスを呼び出す方法を調べてみました。java.netscriptingプロジェクトを見てみると、jruby-engine.jarを手に入れればいいようです。scriptingプロジェクトのメニューにドキュメントという項目があるので、ここからたどって、jsr223-engines.tar.gzをダウンロードしました。~/jsr223というディレクトリを作って、そこでこのファイルを展開すると、jruby/buildディレクトリの中にjruby-engine.jarがありました。後は、jruby.jarとjruby-engine.jarへクラスパスを通してプログラムをコンパイル実行すればいいだけです。次のようにして、RubyのスクリプトをJavaから呼び出せました。

RubyTest.java
public class RubyTest {
    public static void main(String[] args)
    throws javax.script.ScriptException {
        String program = "def hello(n)\n puts n\n end";
        javax.script.ScriptEngine ruby
            = new javax.script.ScriptEngineManager()
                .getEngineByName("jruby");
        ruby.eval(new java.io.StringReader(program));
        ruby.put("s", "Hello JRuby");
        ruby.eval("hello($s)");
    }
}

実行例(~/jsr223/jruby/bin/RubyTest.java)
$ cd ~/jsr223/jruby/bin
$ javac -cp ../lib/jruby.jar:../build/jruby-engine.jar RubyTest.java
$ java -cp .:../lib/jruby.jar:../build/jruby-engine.jar RubyTest
Hello JRuby

 念のため説明をしておくと、「def hello(n)\n puts n\n end」というRubyプログラムをString型の変数「program」へ入れて、ruby.eval()メソッドで実行できるようにしておきます。次に、ruby.put()メソッドで変数「s」へ「Hello JRuby」という文字列を設定しています。最後に、すでに使用可能になっているhelloというプログラムへ、「s」という引数を渡して実行することを、ruby.eval()メソッドにより行っているのです。

 変数の利用については、javax.script.ScriptContextを使って、変数スコープをコントロールしながら使う方法もあります。

RubyTest2.java
public class RubyTest2 {
    public static void main(String[] args)
    throws javax.script.ScriptException {
        javax.script.ScriptEngine ruby
            = new javax.script.ScriptEngineManager()
                .getEngineByName("jruby");
        ruby.getContext().setAttribute("i", new Integer(1),
            javax.script.ScriptContext.ENGINE_SCOPE);
        ruby.eval("puts 2 + $i", ruby.getContext());
    }
}

 参考までに、次の手順でコンソールからのスクリプト実行もできることが分かりました。jruby.shシェルスクリプトの中を見てみると、JDK 6に付属するツールのjrunscriptコマンドを使っていました。

スクリプト実行
$ cp ~/$JRUBY_HOME/lib/jruby.jar ~/jsr223/jruby/lib/
$ chmod 755 ~/jsr223/jruby/bin/jruby.sh; cd ~/jsr223/jruby/bin/
$ echo "puts 'Hello JRuby'" > Hello.rb
$ ./jruby.sh Hello.rb
Hello JRuby

 さて、Javaプログラマ流のRubyプログラミングということで、JRubyの使い方を紹介しました。JRubyについては、Appletで実行されるJRubyインタプリタが公開されていたり、Swingを使ったRubyの実行環境であるJRuby Consoleが開発されていたりと、何かと目が離せません。

 有名なMartin Fowler氏もJRubyを使ってVelocityを簡単に使う方法を考えたりしているようです。実は、Velocityはjava.netのscriptingプロジェクトで対象となっているので、直接使った方がいいのかもしれませんが、このあたりもまだまだ研究の余地が大いにあるということなのでしょう。いずれにせよ、しばらくはJavaとJRubyでいろいろと楽しめそうです。

編集部注Velocityについての詳細を知りたい読者は、「Webアプリケーションフレームワークの定番」の「Velocity」をご参照願います。




筆者プロフィール
小山博史(こやま ひろし)
Webシステムの運用と開発、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。Ja-Jakartaプロジェクトへ参加し、コミッタの一員として活動を支えている。また、長野県の地域コミュニティである、SSS(G)bugs(J)の活動へも参加している。


ご意見、ご感想はJava Solution 会議室へどうぞ


Java Solutionコラム一覧



TechTargetジャパン

Java Solution フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

キャリアアップ

- PR -
@IT Sepcial

イベントカレンダー

PickUpイベント

- PR -
もっと見る
- PR -

お勧め求人情報

ホワイトペーパーTechTargetジャパン

@IT Sepcial
ソリューションFLASH