PR

分散Rubyを実現する

 「呼び出されたメソッドをそのまま他のオブジェクトに転送する」Delegatorの機能はほかにもいろいろと応用できそうです。一例としてdRuby(Distributed Ruby,分散Ruby)を紹介します。

 dRubyはネットワーク経由でメソッドを呼び出すライブラリです。dRubyはサーバー上に存在するリモート・オブジェクトに対応するオブジェクト(Proxy)を作り出し,そのProxyへのメソッド呼び出しをネットワークを越えて転送します。

 呼び出されたメソッドはサーバー上のリモート・オブジェクトで実行され,戻り値が再びネットワークを経由して返ってきます。JavaでいうRMI(Remote Method Invocation)などと似たような仕組みですが,Rubyのメタプログラミング機能を利用して,明示的なインタフェースを定義することなく,任意のオブジェクトのメソッドをネットワーク経由で呼び出せます。

 C++やJavaでのリモート・メソッド呼び出しではIDL(Interface Definition Language)のような言語によってインタフェースを記述し,自動生成されるスタブをコンパイル・リンクしなくてはいけません。これと比較するとなんと簡単に扱うことができるのでしょう。これこそがメタプログラミングの力です。

 dRubyの最初の版は,わずか200行で実装されたのだそうです。これもメタプログラミングの力だと思います。ただし,現在ではdRubyはRubyに標準添付されており,総行数では2000行を越える大規模ライブラリに成長しています。

データベースに応用する

 データベース分野でもメタプログラミングが使われています。

 Webアプリケーション・フレームワークRuby on Rails(RailsまたはRoRと呼ばれる)*2にもメタプログラミングが隠れています(関連記事「生産性の高いWeb開発環境 Ruby on Rails」を参照)。具体的にはデータベース連携ライブラリ(ActiveRecord)が,メタプログラミング機能を使い,簡単にデータベース・レコードと対応するオブジェクトを定義しています。

 図4はActiveRecordを使ったデータベースの定義の例です。これとは別にデータベースにテーブルが定義されているとします。Userクラスに対応するもの(usersテーブル)だけを図5に示しました。

class User < ActiveRecord::Base
 has_one :profile
 has_many :item
end

class Profile < ActiveRecord::Base
 belongs_to :user
end

class Item < ActiveRecord::Base
 belongs_to :user
end
図4●ActiveRecordによるレコード定義の例

CREATE TABLE `users` (

 `id` int(11) NOT NULL auto_increment,
 `login` varchar(80) default NULL,
 `password` varchar(40) default NULL,
 PRIMARY KEY (`id`)

) TYPE=MyISAM;
図5●図4で用いるusersテーブル定義の内容

 図4に示したわずかなコードから,ActiveRecordは,次のような処理を進めます。

(1)クラス(User)とクラス名を複数形にしたテーブル(users)を連携させる。

(2)テーブルのスキーマからレコード内容にアクセスする手段を用意する。

(3)has_one,belongs_toなどの関連指定から,関連するオブジェクトを取り出す手段を用意する。

 このような処理ができるのも,メタプログラミング機能によってクラス名を取り出したり,メソッドを実行時に追加したりできるおかげです。メタプログラミングを応用することで,Railsは生産性の高いWebアプリケーション・フレームワークだという評判が高まっています。

 もちろんRailsが万能で,他のあらゆるフレームワークよりも優れているというわけではありません。しかし,Rubyという言語の特徴を最大限に活用して,非常に高い生産性を確立しているのは確かです。

 Railsについての最新情報は,Webサイトから入手できます。このサイトでは「15分で分かるRails」といった雰囲気で実際にWebアプリケーションを作るビデオを視聴できます。目の前であっという間にWebアプリケーションを作ってしまう様子には感銘を受けます。これは必見です。英語ですが,雰囲気は伝わってきます。

XMLを出力する

 最後に,XMLファイルを出力するためのライブラリを紹介しましょう。Jim Weirich氏が開発したXmlMarkupです。図6のようなプログラムでXMLを簡単に出力(図7)できます。

require 'builder/xmlmarkup'

xm = Builder::XmlMarkup.new(:indent => 2)
puts xm.html {

 xm.head {
  xm.title("History")
 }
 xm.body {
  xm.h1("Header")
   xm.p {
    xm.text!("paragraph with ")
    xm.a("a Link", "href"=>"http://onestepback.org")}
 }
}
図6●XmlMarkupのプログラム例と出力内容

<html>
 <head>
  <title>History</title>
 </head>
 <body>
  <h1>Header</h1>
  <p>
  paragraph with <a href="http://onestepback.org">a Link</a>
  </p>
 </body>
</html>
図7●図6の出力内容

 Builder::XmlMarkupはDelegatorと同様にmethod_missingを用いるテクニックを使っています。メソッド呼び出しによってタグ付きのXMLを出力します。

 タグの付いていないテキストにわざわざtext!を付けなければなりませんが,XMLという人間が書くには手間がかかるフォーマットを,Rubyのブロックを使ってうまく表現しています。