JRakeのより良い実装――JRuby 1.5.0のRake-Ant統合

祝・JRuby 1.5.0リリース!

さて、JRuby 1.5.0は様々な機能拡張が行われているが、その中に次の一文がある。

Ant support and Rake-Ant integration

ほほう?

JRake

JRakeというキーワードが存在する。

JRakeってどうなんだろう? - idesaku blog

Rakeが登場し、アーリーアドプター達から「もしかしてこいつは使えるツールなんじゃあ?」という認識が広まりだした頃、こう考える人が現れた。「JavaプログラムのビルドでRake使えたら幸せになれるんじゃね?」

Rakeを知る身からすれば、そう考えるのは自然なことだと思える。Rakeでは、MakeやApache Antに見られる宣言的な記述と、Rubyを直接利用した手続き型の記述を併用できるため、宣言的な書き方しかできない*1Antでは記述が難しい処理をたやすく記述できる。これは複雑なビルドプロセスを組み立てるにあたって大きな魅力として映る。

しかし、Rakeをそのまま適用するのは難しい。

まず、遅い。Antであれば自分を起動しているJVM内でjavacも呼び出すため、一度起動してしまえばそのあとは高速にコンパイルできる。しかしRakeの場合はjavacコマンドを外部コマンドとして実行することになるため、実行のたびに新しくJVMが起動することになる。これはいくらなんでもオーバーヘッドがでかすぎる。

また、長らく使われ続けているJavaおよびAntには膨大なソフトウェア資産があるのだが、Rakeからそれらを直接使うことは難しい。そこに使える資産があるのに、Rakeを使用しているというだけで同様の機能を持つライブラリを余所から調達するか、自分で書かねばならない。

そこでJRubyである。JRuby上で実行されたRubyスクリプトでは、Javaのライブラリを直接利用することが可能となる。つまり、RakeをJRubyで実行すれば(JRuby + Rake = JRake)、上記した問題のいくつかを解消できるのである。例えば、javac呼び出しのオーバーヘッドはcom.sun.tools.javac.Mainクラスを直接使うことで無くせるし、既存のJavaライブラリも使用可能だ。

しかし、多少ハックくさい記述をしなければならず、使い勝手が良いかと言われると首をかしげてしまう。また、JavaライブラリではなくAntのタスクをそのまま使いたい場合も多々あろうが、それはJRakeであっても難しい。

こうした欠点があるため、結局は多少無理してでもAntを使い続けたほうが面倒が無くて良い、という考えに落ち着いてしまう。

JRuby 1.5.0のRake-Ant統合

ところが、今バージョンのRake-Ant統合により、より簡単できれいな記述でRakeからAntを利用できるようになったのである。

正式なリファレンスがどこにあるのかわからないが、とりあえず次の記事の内容通りに書いてみたら、ちゃんと動いた。

日本語JRuby: RakeとAntを一緒に

記事に必要十分な記載があるので是非読んでいただきたいが、簡単に言うとこんなことができるのである。

require 'ant'

ant.javac :srcdir => "./src", :destdir => "./dest", :includeAntRuntime => false

Rubyスクリプトから、AntのJavacタスクを呼び出している。これをRakefile内で使えば…。

require 'ant'
require 'rake/clean'

SRC_DIR = "./src"

DEST_DIR = "./dest"
directory DEST_DIR

CLEAN << DEST_DIR

task :default => :compile

desc "compile with ant javac task"
task :compile => DEST_DIR do
  ant.javac(:srcdir => SRC_DIR, :destdir => DEST_DIR, :includeAntRuntime => false)
end

このように、Rakeで片付けられるところはRakeに任せて、Antが必要な場面ではピンポイントで簡単に任意のタスクなりターゲットなりを呼び出せる。冗長な書き方を要求されるAntのプロパティも不要だ、Rubyの変数をそのまま使えばいい。なるほど、構文もスマートで、無理矢理感も無いし、良いではないか!

他にも、こんなことができるそうだ。

  • RakeでAntで定義されているタスクとタイプを呼ぶ。
  • AntからRakeを呼べるようにする。
  • Rake のタスクをAntのターゲットとしてインポート出来るようにする。
  • RakeからAntを呼べるようにする。
  • Ant のターゲットをRakeのタスクとして呼べるようにする。
日本語JRuby: RakeとAntを一緒に

RakeからAntを使える、というだけではなく、その逆も可能であるということだ。そのため、先ほどRakeをメインに使いつつAntのタスクを併用する、という例を示したが、逆に既存のbuild.xmlをメインとしつつ、Antでは記述が難しい部分だけをRakefileとして書く、といった運用も可能である。

RakeとAntを併用するに当たってどちらをどれだけ使用するかは、自分のスキルやプロジェクトの都合に合わせて任意に調整すればいい。そうすることが可能になるほどにシームレスに統合されているのだ。

また、Rakeにbuild.xmlを取り込んだり、逆にAntにRakefileを取り込んだりもできる。これは、既存プロジェクトで作り上げてきた資産をそのまま生かすことができることを意味するわけで、ますます適用が容易である。まったく至れり尽くせりだ。

ライブラリの依存性解決も

また、見ての通り ant.XXX の記法でAntのタスクを簡単に呼び出せるよう設計されているわけだが、これはAnt標準のタスクだけでなく、taskdefで追加した拡張タスクも対象となっている。つまり、膨大なAnt資産を即、使用できるのだ!

例えば、JRuby 1.5.0 + Rake + Ant + Apache Ivyの組み合わせで、ライブラリの依存性解決もサポートできるという。

道具箱に新しいJRakeを!

このように、JRuby 1.5.0ではJRakeをJavaプロジェクトの構成管理に取り入れるに当たって発生するであろう障害の多くを取り払っている。Rake、しいてはRubyの記述力の恩恵を、Java世界にももたらすのだ!

とはいえ、一昔前とは異なり、Antに手続き型の手法を導入する手段はJRakeだけではない。

例えばGroovyスクリプトbuild.xmlに記述することはできるし、build.xml全体をGroovyによるDSLで書くGantのようなツールも存在する。また、Apache Buildrという、pom.xmlRubyで記述できるMaven、といった案配のツールまである。他にもあるかもしれない。選択肢はいろいろだ。

しかし、それらを考慮しても、JRuby 1.5.0のRake-Ant連携はなお魅力的である。記述力が高く、学習コストも低く、既存プロジェクトへの適用も容易だ。よって、環境やスキルがマッチするなら、導入を検討する価値はあるように思える。そして、使えるぞ!という時のために、自分の道具箱の片隅に新しいJRakeを忍ばせておいても良いのではないだろうか。

*1:これは設計上の選択であって、意図的にそのように実装してあるそうだ。