9
ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016 50 //jvm languages / J Rubyチームは5月、JRuby 9000系の最新バージョンであるJRuby 9.1を リリースしました。公開されているRuby実装の中でJRuby 9000が最良 のものとなるように、チームは懸命に取り組みました。JVM上で動作する Ruby、特にJRubyの使用を検討することをお勧めする理由を、このチーム のメンバーである筆者が実例を交えて紹介します。 Rubyとは Rubyは、Smalltalk、Perl、およびLispの影響を受けた、オブジェクト指向の 動的型付け言語です。Matzこと、まつもとゆきひろ氏が1995年に作成した Rubyの現行バージョンは2.3です。Ruby on Railsと呼ばれるWebフレームワ ークのおかげもあり、Rubyは過去10年にわたり、人気言語のトップ10にラン クインしてきました。最近では、世界最大規模の企業の一部でRubyが使用 されており、使用目的もWeb開発だけではありません。 残念ながら、Rubyの標準実装(通常、CRubyまたはMRI (Matz’s Ruby Implementation)と呼ばれる実装)には、高速なJIT(just-in-time)コンパ イラ、休止時間の短いスケーラブルなガベージ・コレクション、真のパラレル 実行など、最近の開発者が求め、たびたび必要となるいくつかの機能があ りません。そこで登場するのがJRubyです。 JRubyとは JRubyはJVM上にRubyを実装したもので、大半がJavaで記述(ただ し、Rubyによる記述も徐々に増えています)され、Rubyの機能の99%がサ ポートされています。JRubyチームは、JVMの機能を活用しながらも、JRuby とCRubyの互換性をできる限り維持しようと努めています。 JRubyのガベージ・コレクタはJVMのガベージ・コレクタであり、現在の JVMでは多数の優れたガベージ・コレクタを使用できます。【編集注:Java Magazine日本版 Vol.26に「OpenJDKの新しいガベージ・コレクタ 」(著 者:Christine Flood)という記事があります。いくつかのJVMガベージ・コレ クタの比較について詳しくは、この記事を参照してください】JRubyのスレ ッドはJVMスレッドであるため、Rubyコードは真にパラレルで実行されま す。JRubyでRubyコードからコンパイルされたJVMバイトコードは、JITでネ イティブ・マシン・コードにコンパイルできます。実際、ネイティブJITのあら ゆる機能を持つ最初のRuby実装がJRubyだったのです。 こうした機能のすべてが一体となって極めて強力なツールが生まれまし た。Rubyをプログラミングすることの魅力と楽しさに、JVMの長所が組み 合わされたのです。それでは、このツールで何ができるのでしょうか。 使用の開始 JVMベースのほとんどのライブラリやアプリケーションと同様に、JRubyは いくつかのビルト済みバイナリ形式で配布されています。 http://jruby.orgから入手できる、JRubyの完全ディストリビューションに は、コマンドライン・ユーティリティ(rubyコマンドやgemコマンドなど) 、Ruby標準ライブラリ、CRubyに似たファイル・システム・レイアウトが含ま れています。ほとんどのユーザーには、この完全ディストリビューションをお 勧めします。また、RVMなどのいわゆる”Rubyスイッチャ”を使用することを お勧めします。Rubyスイッチャを使用すると、最新のJRuby実装がダウンロ ードされてインストールされます。 CHARLES NUTTER JRuby 9000:魅力的な言語、 強力なランタイム Ruby on Rails誕生のきっかけであり、JavaFXの開発といった複雑なJavaコーディングを ネイティブ・ライブラリで大幅に簡略化できるシンプルな言語

JRuby 9000:魅力的な言語、 強力なランタイム

Embed Size (px)

Citation preview

Page 1: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

50

//jvm languages /

JRubyチームは5月、JRuby 9000系の最新バージョンであるJRuby 9.1をリリースしました。公開されているRuby実装の中でJRuby 9000が最良のものとなるように、チームは懸命に取り組みました。JVM上で動作するRuby、特にJRubyの使用を検討することをお勧めする理由を、このチームのメンバーである筆者が実例を交えて紹介します。

RubyとはRubyは、Smalltalk、Perl、およびLispの影響を受けた、オブジェクト指向の動的型付け言語です。Matzこと、まつもとゆきひろ氏が1995年に作成したRubyの現行バージョンは2.3です。Ruby on Railsと呼ばれるWebフレームワークのおかげもあり、Rubyは過去10年にわたり、人気言語のトップ10にランクインしてきました。最近では、世界最大規模の企業の一部でRubyが使用されており、使用目的もWeb開発だけではありません。残念ながら、Rubyの標準実装(通常、CRubyまたはMRI(Matz’s Ruby Implementation)と呼ばれる実装)には、高速なJIT(just-in-time)コンパイラ、休止時間の短いスケーラブルなガベージ・コレクション、真のパラレル実行など、最近の開発者が求め、たびたび必要となるいくつかの機能がありません。そこで登場するのがJRubyです。

JRubyとはJRubyはJVM上にRubyを実装したもので、大半がJavaで記述(ただし、Rubyによる記述も徐々に増えています)され、Rubyの機能の99%がサポートされています。JRubyチームは、JVMの機能を活用しながらも、JRubyとCRubyの互換性をできる限り維持しようと努めています。

JRubyのガベージ・コレクタはJVMのガベージ・コレクタであり、現在のJVMでは多数の優れたガベージ・コレクタを使用できます。【編集注:Java Magazine日本版 Vol.26に「OpenJDKの新しいガベージ・コレクタ」(著者:Christine Flood)という記事があります。いくつかのJVMガベージ・コレクタの比較について詳しくは、この記事を参照してください】JRubyのスレッドはJVMスレッドであるため、Rubyコードは真にパラレルで実行されます。JRubyでRubyコードからコンパイルされたJVMバイトコードは、JITでネイティブ・マシン・コードにコンパイルできます。実際、ネイティブJITのあらゆる機能を持つ最初のRuby実装がJRubyだったのです。こうした機能のすべてが一体となって極めて強力なツールが生まれました。Rubyをプログラミングすることの魅力と楽しさに、JVMの長所が組み合わされたのです。それでは、このツールで何ができるのでしょうか。

使用の開始JVMベースのほとんどのライブラリやアプリケーションと同様に、JRubyはいくつかのビルト済みバイナリ形式で配布されています。http://jruby.orgから入手できる、JRubyの完全ディストリビューションには、コマンドライン・ユーティリティ(rubyコマンドやgemコマンドなど)、Ruby標準ライブラリ、CRubyに似たファイル・システム・レイアウトが含まれています。ほとんどのユーザーには、この完全ディストリビューションをお勧めします。また、RVMなどのいわゆる”Rubyスイッチャ”を使用することをお勧めします。Rubyスイッチャを使用すると、最新のJRuby実装がダウンロードされてインストールされます。

CHARLES NUTTER

JRuby 9000:魅力的な言語、 強力なランタイムRuby on Rails誕生のきっかけであり、JavaFXの開発といった複雑なJavaコーディングを ネイティブ・ライブラリで大幅に簡略化できるシンプルな言語

Page 2: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

51

//jvm languages /

$ rvm install jruby-9.1.2.0Searching for binary rubies, this might take some timeFound remote file /Users/headius/.rvm/... Checking requirements for osx.Requirements installation successful.jruby-9.1.2.0 - #configurejruby-9.1.2.0 - #downloadjruby-9.1.2.0 - #validate archivejruby-9.1.2.0 - #extractjruby-9.1.2.0 - #validate binaryjruby-9.1.2.0 - #setup...

詳しくは、RVMのホームページを参照するか、他のRubyスイッチャのいずれかを試してください。もっと直接的なやり方がよければ、JRubyの完全ディストリビューションを含むtarball(.tar.gz)またはzipファイルをダウンロードするだけでも構いません。ファイルを解凍し、PATHにbinディレクトリを追加すれば、準備完了です。JRubyにはWindowsインストーラも用意されており、任意でJREもインストールできます。また、”org.jruby”グループの下でバラバラになったライブラリすべてのMavenアーティファクトが公開されています。このアーティファクトは、完全なJRubyディストリビューションがファイル・システム上になくてもよい埋込みアプリケーションに便利です。インストールが完了したら、JRubyのコマンドラインはCRubyのコマンドラインと一致します。

$ jruby -vjruby 9.1.2.0 (2.3.0) 2016-05-26...$ jruby -e "puts 'Hello, Ruby'"Hello, Ruby

また、Rubyの対話型コンソールであるIRBも使用できます。

$ irbjruby-9.1.2.0 :001 > puts "hello"

hello...

Ruby on RailsWeb開発者なら誰でも、Ruby on Railsはすでに耳にしたことがあるでしょう。わかりやすいデフォルト(設定より規約)という概念や充実したコード生成機能(scaffoldによるひな形の作成)、データベースにとらわれないスキーマ・バージョニング(マイグレーション)が導入されたことで、Web開発のやり方が変わりました。現在あるWebフレームワークのほとんどは、何らかの点でRailsを手本にしています。中には、Railアプリケーションのファイル・システム・レイアウトを模倣しているものや、Railsの影響を受けた用語を類似機能に再利用しているものさえあります。次に、簡単なRailsアプリケーションをJRubyで実行する手順を説明します。しかしその前に、gem installコマンドを使用してRailsをインストールする必要があります。Ruby用のライブラリのほとんどは、RubyGems.org上でホストされる”gem”として配布されます。Javaの観点から見た場合、Ruby gemはMavenライブラリにコマンドラインの実行可能スクリプトをいくつか加えたものと考えてください。

$ gem install railsFetching: rack-1.6.4.gem (100%)Successfully installed rack-1.6.4Fetching: sprockets-3.6.0.gem (100%)Successfully installed sprockets-3.6.0...Fetching: rails-4.2.6.gem (100%)Successfully installed rails-4.2.623 gems installed

$ rails new my_app create create README.rdoc create Rakefile... create vendor/assets/stylesheets

Page 3: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

52

//jvm languages /

create vendor/assets/stylesheets/.keep run bundle installFetching gem metadata from https://rubygems.org/Fetching version metadata from https://rubygems.org/Fetching dependency metadata from https://rubygems.org/Resolving dependencies..............Using i18n 0.7.0Using json 1.8.3Installing minitest 5.9.0...Installing sass-rails 5.0.4Installing turbolinks 2.5.3Bundle complete! 11 Gemfile dependencies, 54 gems now installed.Use 'bundle show [gemname]' to see where a bundled gem is installed.

【編集注:誌面の制約により、この出力および本記事の他の出力に含まれる行の一部で切捨てや改行が行われています。また、不要なデータは削除されています】Railsの手品が始まるのはここからです。rails newコマンドを使用する

と、ようこそページ、規約に基づいたファイル・システム・レイアウト、sqlite3を使用する基本的なデータベース設定(-dフラグを使用して別のデータベースを指定できます)が揃った、必要最小限の機能を持ち十分に機能するアプリケーションができあがります。アプリケーションが構築されると、次はbundleコマンドが実行されます。Bundlerは、アプリケーションの依存性をgem単位で管理するツールです。Railsで作成されるGemfileには、アプリケーションに必要なすべてのライブラリのリストが含まれており、Bundlerが確実にそれらのライブラリをインストールしてくれます。ロジックを一切記述していなくても、この時点でRailsアプリケーションを起動できます。

$ cd my_app$ rails server=> Booting WEBrick=> Rails 4.2.6 application starting in

development on http://localhost:3000=> Run 'rails server -h' for more startup options=> Ctrl-C to shutdown server[2016-06...] INFO WEBrick 1.3.1[2016-06...] INFO ruby 2.3.0 (2016-06-06) [java][2016-06...] INFO WEBrick::HTTPServer#start: pid=37393 port=3000

ここで、scaffoldを使用してこのアプリケーションにいくつかの基本的な機能のひな形を手早く作成します。Railsで言うひな形とは、開発時に生成されるコードのことで、アプリケーションのおおまかな構造がこのコードにより準備されます。モデル、ビュー、コントローラ、テストなどの生成をRailsに指示できます。次の例では、”title”と”body”を伴う”post”に対応するCRUD操作の基本コードを生成しています。

$ rails generate scaffold post title body:text invoke active_record create db/migrate/20160606083900_create_posts.rb create app/models/post.rb invoke test_unit create test/models/post_test.rb create test/fixtures/posts.yml invoke resource_route route resources :posts invoke scaffold_controller create app/controllers/posts_controller.rb invoke erb create app/views/posts create app/views/posts/index.html.erb create app/views/posts/edit.html.erb create app/views/posts/show.html.erb create app/views/posts/new.html.erb create app/views/posts/_form.html.erb invoke test_unit create

Page 4: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

53

//jvm languages /

test/controllers/posts_controller_test.rb...

scaffoldを実行したことで、実際のアプリケーション・コードとテストの他にデータベース・マイグレーションと呼ばれるものが生成されました。データベース・マイグレーションとは、データベース・スキーマの1つのバージョンを選んで次のバージョンへのマイグレーションに必要な変更を適用できる短いスクリプトのことです。このマイグレーションという操作により、データベースにとらわれずにスキーマのロールバック/ロールフォワードが可能になります。ここで必要なのは、データベース・マイグレーションをロールフォワードしてサーバーを再起動することだけです。

$ rake db:migrate== 20160606083900 CreatePosts: migrating =========-- create_table(:posts) -> 0.0075s -> 0 rows== 20160606083900 CreatePosts: migrated (0.0099s)

$ rails server=> Booting WEBrick...

ここではrakeコマンドを使用しています。このコマンドは、依存性の管理がないという点を除き、AntまたはMavenを使用するのとほぼ同じです。Railsを最新のデータベース・スキーマにマイグレーションしたらサーバーを起動できるようになり、CRUD操作ができる基本的なWeb GUIがすぐに完成します。Railsは今でもRubyのキラー・アプリケーションです。Railsをまだ試していないのであれば、JRubyを口実にして今すぐRailsを試してみてはいかがでしょう

か。Railsのサイトに用意されている優れたドキュメントやチュートリアルをチェックするか、ちまたに出回っているRails関連書籍のどれか1冊を手に取ってみてください。さて、キラー・アプリケーションはもうできています。次はデプロイですが、JRubyではどのようにデプロイするのでしょうか。

JRubyへのRailsのデプロイCRubyでは、リクエストをパラレルに処理する場合は、独立したプロセス、つまり何もリソースを共有しない完全に独立したVMを起動する必要があります。そのため、小型のアプリケーションであってもメモリ消費量が増え、通信が必要な場合は何らかのプロセス間通信を使用せざるを得ません。データベースやmemcachedなど、第3のプロセスでは読取り専用のアプリケーション構造体しか共有されないため、これらのプロセスではデータ共有の口を別プロセスで起動する必要があります。そして、それぞれが独自のヒープとガベージ・コレクタを持つRubyの仮想マシンが大量に稼働することになります。このようなリソースの使い方は、このマルチコアの時代において最善とは言えません。JRubyでは、この同じRailsアプリケーションを使用してロード全体をシングル・プロセス内で処理できます。このとき使用されるのは並行処理に合わせて調整された1つのガベージ・コレクタとスケーラブルなヒープです。この1つのプロセスはスタンドアロン・サーバーでも構いませんが、TomcatやWildFlyなど任意の標準Webコンテナに”JRuby on Rails”をJava WARファイルとしてデプロイすることもできます。RubyまたはJavaのいずれかからJRubyにたどり着いた場合でも、JRubyアプリケーションのデプロイメントは環境に適合し、ハードウェアの活用効率が向上します。シンプルなスタンドアロンでの使用の場合は、Puma gem(もっとも使用されている純粋なRuby Webサーバー)を一般的にはお勧めします。

$ gem install pumaFetching: puma-3.4.0-java.gem (100%)Successfully installed puma-3.4.0-java1 gem installed$ pumaPuma starting in single mode...* Version 3.4.0 (jruby 9.1.3.0-SNAPSHOT - ruby 2.3.0), codename: Owl Bowl Brawl

JRubyは他のJVM言語との双方向の統合をサポートしています。そのため、使い慣れたすべての

Javaライブラリを引き続き

自分のツールボックスに置

いておくことができます。

Page 5: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

54

//jvm languages /

* Min threads: 0, max threads: 16* Environment: development* Listening on tcp://0.0.0.0:9292Use Ctrl-C to stop

既存のJavaアプリケーション・サーバーまたはWebコンテナにデプロイする必要がある場合は、Warbler gemを使用してRailsアプリケーション(およびそのすべての依存性)をデプロイ可能なWARファイルにパッケージ化します。

$ gem install warblerFetching: rubyzip-1.2.0.gem (100%)Successfully installed rubyzip-1.2.0Fetching: jruby-rack-1.1.20.gem (100%)Successfully installed jruby-rack-1.1.20Fetching: jruby-jars-9.1.2.0.gem (100%)Successfully installed jruby-jars-9.1.2.0Fetching: warbler-2.0.3.gem (100%)Successfully installed warbler-2.0.34 gems installed$ warblerm -f my_app.warCreating my_app.war

たったのこれだけです。

Javaの記述JRubyには、RubyやRailsの開発者をさらに魅了する機能が他にもあります。JVM上のどのライブラリでも、別のRubyコードであるかのように呼び出せる機能です。JRubyは他のJVM言語との双方向の統合をサポートしています。そのため、使い慣れたすべてのJavaライブラリを引き続き自分のツールボックスに置いておくことができます。実際、JavaライブラリをJRubyで記述するのは、Javaコードを書くよりもはるかに楽しく簡単なことがよくあります。いくつか例を見てみます。

java_import java.lang.System

Frame = javax.swing.JFrameButton = javax.swing.JButtonLabel = javax.swing.JLabel

frame = Frame.new("Java Home Checker")button = Button.new("Display Java Home")label = Label.new

button.add_action_listener do label.text = System.get_property('java.home')end

frame.content_pane.layout = java.awt.FlowLayout.newframe.content_pane.add(button)frame.content_pane.add(label)

frame.set_default_close_operation(Frame::EXIT_ON_CLOSE)frame.set_size(500, 100)frame.visible = true

sleep

JRubyの長所の一部は、すでにこの簡単な例に表れています。具体的に言えば、importは単なるプレーンなRubyコードです。このコードでは、クラスをインポートする方法として、java_import関数を使用するやり方と、完全修飾した長いクラス名をそのまま使用(して短い名前に割当て)するやり方の2つが使われています。Javaのメソッド名は、Rubyのメソッド名らしく見えるようにするために少し手が加えられ、キャメルケースの代わりにスネークケースが使用されています。プロパティのset/getは、set/getを省略して属性名だけで呼び出すことができ、括弧はオプションです。実際、Swingになじみがなければ、このコードがJavaライブラリを呼び出すことさえわからないでしょう。簡単なインタフェースなら、Java 8のラムダ式に似たコード・ブロックを渡せばすぐに実装できます。しかしJRubyでは、インタフェース

Page 6: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

55

//jvm languages /

実装を任意のオブジェクトに動的に追加することもでき、(通例に従い、method_missingによるフォールバックを含めた場合は)すべてのメソッドを実装する必要はありません。このコードのノイズや作法は、Javaバージョンのコードよりはるかに少なくなっています。それでは、JRubyとJavaとの統合によりできることは何なのか、少し高度な例をいくつか見ていきます。

JRubyFX2008年の末に、Sun MicrosystemsがJavaFXの最初のバージョンをリリースしました。これは、Swingの後継となる、Webテクノロジーから着想を得た新しいGUIツールキットでした。当初、JavaFXには独自言語であるJavaFX Scriptが使用されていましたが、言語の選択肢がすでに過剰であったため、現在も使用されているのはGUIツールキットのみです。つまり、JavaFXのロジックの記述にはJavaを使用するということです。おそらく、ここでもJRubyが少し役に立つはずです。JRubyFXと入力します。JRubyFXは、JavaFXアプリケーションを記述するためのRuby APIでありラッパーです。簡単な例を見ていきます。

01 require 'jrubyfx'0203 class HelloWorldApp < JRubyFX::Application04 def start(stage)05 stage.title = "Hello World!"06 stage.width = 80007 stage.height = 60008 stage.show()09 end10 end1112 HelloWorldApp.launch

1行目にはjrubyfxが必要です。これで一連のJavaFXライブラリをバインドし、JavaFXの機能を使用できるようにします。Rubyでは、requireを使用してプロセスにライブラリを取り込みます。このライブラリは通常、Rubyのソースとしてローカル・ファイル・システムにインストールされますが、他の

言語で記述された拡張機能を併せて取り込むこともあります。3行目には、JRubyFX::Applicationクラスを拡張するRubyクラスの

定義があります。Rubyのクラスは、Javaと同様にclassキーワードを使用して宣言しますが、Rubyではextendsキーワードの代わりに小なり記号(<)を使用します。2つのコロンは、Rubyでネームスペースを示すときのやり方です。1つ目のメソッド定義は4行目にあります。Rubyは動的に型付けを行うため、メソッドの戻り値やパラメータの型宣言は行いません。5行目から8行目はステージのセットアップです。(Javaの”set”メソッドではなくRuby方式の属性割当てを使用して)タイトルとウィンドウのサイズを設定し、JavaFXにステージを表示するよう指示しています。9行目と10行目でメソッドとクラス定義を終了しています。Rubyではほとんどのレキシカル・スコープをendキーワードで閉じますが、とはいえ、短いブロック(ラムダ式)には波括弧をよく使用します。最後の12行目では、新しいJRubyFXアプリケーションに対してアプリケーション自体を起動するように指示しています。それほど簡単なのです。それでは、どうしてRubyでアプリケーションの記述を本当に楽しく簡単にすることができるのかを見てみます。

def start(stage) with(stage, title: "Hello World!") do layout_scene(800, 600) do label("Hello World!") end end stage.show # you can also put the # method call inside the blockend

このstartメソッドは少し複雑です。もっともわかりやすい変更箇所はwithの呼出しです。withはJRubyFXのシーン作成DSLを使用したコード・ブロックを受け取ります。JavaFXでセットアップしたStageとタイトルを指定し、ステージのコンテンツの作成に進みます。DSLにこのシーンのレイアウト方法を指示し、実際のコンテンツ(JavaFXラベル)を追加します。シーンを記述するために使用する、JavaFXのXMLベースのマークアップであるFXMLはどうでしょうか。Rubyでシーンを作成するのはとてもよいこと

Page 7: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

56

//jvm languages /

です(また、Javaで作成するより労力が大幅に少ないことも確かです)が、大規模なアプリケーションの場合はおそらく、アプリケーション・コードとは別にGUIを記述した方がよいでしょう。次に示すのは、簡単なシーンのFXML定義です。

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?><?import java.util.*?><?import javafx.scene.control.*?><?import javafx.scene.layout.*?><?import javafx.scene.paint.*?><?import javafx.scene.text.*?>

<HBox alignment="CENTER" xmlns:fx="http://javafx.com/fxml"> <children> <Label text="Hello World!!" underline="true"> <font> <Font size="66.0" /> </font> </Label> </children></HBox>

JRubyFXでこの定義を使用するのは、次に示すとおり、fxmlメソッドの呼出しを追加するのと同じくらい簡単です。

def start(stage) with(stage, title: "Hello World!", width: 800, height: 600) do fxml "Hello.fxml" show endend

JRubyとJavaFXの連携は非常によいため、これまでJavaFXを試す機会がなかったのであれば、JRubyFXが今週一番の楽しみとなるかもしれません。詳しくは、JRubyFXの充実したGetting Startedページを確認してください。

JVM以外への取り組み懸命な取り組みにより、JRubyは可能な限り純粋なJava(といくらかのRuby)に維持されており、LinuxからOpenVMSに至る多様なプラットフォームのユーザーがJRubyを使用できるようになっています。プラットフォーム非依存というJavaの特徴は、この点で役に立っています。ただし、この非依存という特徴は、ネイティブ・アプリケーション(すなわち、このケースではCRuby)でできるほどうまくホスト・プラットフォームと統合できないことを意味する場合もあります。JRubyの互換性レベルを高く維持するためには、ネイティブ・ライブラリを呼び出すことが必要になる場合がよくあります。通常、JVMの場合にこれが意味することは、Javaから呼び出されるすべての関数のJavaネイティブ・インタフェース(JNI)コードを大量に記述することであり、すべてのサポート対象プラットフォームのコードをビルドすることであり、この膨らむ一方のバイナリをJRubyと一緒に配布することです。このようなアプローチにスケーラビリティがないことは明白であるため、JRubyチームは別のアプローチとして、Javaネイティブ・ランタイム(JNR)を使用して実行時にライブラリを動的にロードしてバインドする方法を採用しています。Java Native Access(JNA)についてはすでによくご存じかもしれませんが、JNRはJNAと同様に、libffi(ほとんどのUNIXプラットフォームで使用される他言語関数インタフェース(FFI)ライブラリ)の低レベル・バインディングを使用してライブラリを組み込み、必要な関数を検索し、Javaインタフェースにバインドします。JRubyでは、大量のPOSIX関数、UNIXソケット・サポート、ネイティブI/Oファイル記述子などを取り込んでバインドします。Rubyistであれば、ffi gem(ネイティブ・ライブラリを呼び出せる使い勝手のよいRuby API)を介してJRubyのネイティブ・サポートを利用することもできます。require 'ffi'

module POSIX extend FFI::Library attach_function :getuid, :getuid, [], :uint attach_function :getpid, :getpid, [], :uint

Page 8: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

57

//jvm languages /

end

pid, uid = POSIX.getpid, POSIX.getuidputs "Process #{pid} running as user #{uid}"

この例では、ネイティブ関数バインディングを保持するために必要なRubyモジュールを作成しています。モジュールは、すべてのメソッドがデフォルト実装されたインタフェースだと考えてください。メソッドは、クラス・メソッド(Javaの静的メソッドに似たもの)の場合もインスタンス・メソッドの場合もあり、これらはモジュールが組み込まれるときにクラス階層に追加されます(Javaにインタフェースを実装する場合と同様です)。次のリストでは、LibCモジュール内部でFFI::Libraryモジュールを拡張し、関数のバインドやネイティブ・データ型の定義に使用できる他のFFIメソッドをインジェクションしています。これで、前述のリストからattach_functionにアクセスできます。attach_functionに引数として渡すのは、呼び出す関数の名前、その関数に割り当てるRuby名(オプション)、パラメータの型に関する情報です。以上で完成です。このコードをJRuby上で実行すると、ホストJVMにおける実際の生のプロセスIDとユーザーIDを確認できます。これは、純粋なJavaコードではできないことです。

class Timeval < FFI::Struct layout :tv_sec => :ulong, :tv_usec => :ulongend

module LibC extend FFI::Library attach_function :gettimeofday, [ :pointer, :pointer ], :intend

t = Timeval.newLibC.gettimeofday(t.pointer, nil)puts "t.tv_sec=#{t[:tv_sec]} \ t.tv_usec=#{t[:tv_usec]}"

JRubyのFFIを使用して、構造体などのネイティブ・データ型を定義することもできます。前述のコードでは、Timeval構造体を定義しています。この構造体は、メモリ内レイアウトとして2つのunsigned long、tv_secとtv_usecを持ちます。libc gettimeofday関数をバインドし、Timevalの新しいインスタンスを作成し、呼出しを行います。ネイティブ呼出しによりネイティブ構造体が移入されるため、これを通常のRubyオブジェクトのように読み込むことができます。しかも、Cコードを1行も書かずにです。実に素晴らしいと思いませんか。FFIでできることは他にもたくさんあり、JRubyのネイティブ機能を活用している大型の本番アプリケーションも多数あります。詳しくは、Ruby FFI プロジェクトを参照してください。

JRuby 9000の今後JRuby 9000は、公開されているJVM言語実装の中でも特に先進的なものの1つで、バイトコードに似た独自の中間表現を使用し、最適化コンパイラがあり、JITコンパイラを組み合わせた混合モードのインタプリタ(JVMそのものに酷似)も備えています。JRubyチームはJVM上で言語ができることの限界を打破し続けてきました。実際、JRubyは現在公開されているものの中でもっとも速いRuby実装です。内部表現(IR)ランタイムを利用すれば、Rubyならではの特徴を1つも犠牲にせずに、すべてのJRubyコードのパフォーマンスを同等のJavaコードに匹敵するほどに引き上げられるでしょう。JRubyチームは、今年末までにこれを実現したいと考えています。しかし、JRubyチームの歩みがそこで止まるわけではありません。2014年の終わりに、JRubyチームはOracle Labsとパートナーを組み、JRubyプロジェクトの一環としてTruffleベースのRuby実装をオープン・ソース化しました。TruffleはJVMのバイトコードと共生する次世代言語ランタイムですが、純粋なJavaで書かれたGraalというJITコンパイラを使用して言語の動作を直接最適化します。そのため、Graalと相性がよいJDK 9などのJVM上で実行することが要件とはなりますが、JRubyとTruffleの組合せならどのランタイム上でもRubyを一番速く実行できることが証明されるかもしれません。JRubyチームは、JRubyとTruffleを組み合わせたランタイムを、今後数年以内に本番投入できる状態にしたいと考えています。IRランタイムも非常に楽しみですが、Truffleの可能性にもJRubyチームは大きな期待を寄せています。Rubyはもはや遅い言語ではありません。

Page 9: JRuby 9000:魅力的な言語、 強力なランタイム

ORACLE.COM/JAVAMAGAZINE /////////////////////////////// JULY/AUGUST 2016

58

//jvm languages /

まとめRubyは、充実したエコシステムと、好意的で協力的なコミュニティを持つ魅力的で楽しい言語です。Railsはこのコミュニティのおかげで現在あるような強力なツールになり、適切に構造化されたWebアプリケーションをもっとも短期間で本番環境にデプロイできるようになりました。JRubyを使用すれば、Rubyの世界の利点とJavaの世界の利点を活用できます。つまり、同じサーバーにデプロイでき、同じライブラリを使用でき、JVMの能力を最大限に引き出すことができます。それも、楽しんでできるかもしれません。この機会にぜひJRubyに挑戦してみてください。</article>

Charles Nutter:Red HatでJVM言語を担当し、思うままにJVMを操るJava Champion。これまで10年間にわたりJRubyプロジェクトの共同責任者を勤め、それまでは長年Java EEのリード・アーキテクトとしてプロジェクトに従事。Javaプラットフォームが今後もオープンであり発展し続けることを望み、新しい言語とソフトウェア構築方法に対応できるよう、プラットフォームの拡充に取り組んでいる。

Home of the Ruby language (non-JVM)Truffle on the JDK

learn more

//user groups /

BUCHAREST JUGルーマニアのブカレストはソフトウェア開発の中心地です。Bucharest Javaユーザー・グループは、JavaベースおよびJVMベースのプログラミング言語を使用するブカレストの開発者のために強力なコミュニティを作ることを目的に設立されました。最初の会合が開かれたのは2012年5月で、参加者はおよそ25

人でした。現在このJavaユーザー・グループ(JUG)のリーダーを務めるのはAlex Proca氏とAlin Pandichi氏で、登録メンバーは600人を超えています。会合は毎月開催され、1つか2つのプレゼンテーションが行われます。午後7時頃から始まる会合の後は、パブに場所を移して飲み会が開かれます。時折ハンズオン・ラボも行われ、最近ではMVC 1.0(JSR 371)Java EE仕様とJavaFXに関するワークショップが開催されました。講演には毎回50人前後が出席し、ワークショップには10人前後が出席します。講演者は地元の優秀なJava開発者の中から選ばれることが多く、たとえばEugen Paraschiv(別名Baeldung)氏のチュートリアルやレビューはかなりの人気となっています。時には国外から講演者を招くこともあり、Java ChampionのAxel Fontaine氏の講演会ではイミュータブル・インフラストラクチャ(不変のインフラ)に関するプレゼンテーションが行われました。このJUGの活動を通じてJavaに対する地元の関心が高まり、Voxxed Days BucharestというJavaカンファレンスが企画されるまでになり、2016年3月に第1回が開催されました。主催者はすでに来年のイベントを心待ちにしています。Bucharest JUGは世界中のJavaコミュニティのメンバーと頻繁に連絡を取り合っています。詳しくは、メールで問い合わせるか、Twitter、Facebook、 Google+、またはMeetupをフォローしてください。