日本からも何人かの技術者が参加したらしい先月末に行われた Ruby on Rails と Ruby 関連の会議 RailsConf 2008 (5月29日〜6月〜1日) からか、週一回程度、ブログで開発版の Rails の更新点を的確な形で紹介しているチュー・ヤオさん (”Chu Yeow”) が、Ruby on Rails の公式ブログ Riding Rails に参加した様で、公式ブログでも開発版の変更点や更新点が気軽に確認できるようになった様です。

 もっとも、実務で開発している方々の多くが開発版の Rails を現場で使っていると思いませんし、Rails に直接コントリビュートしている人は IRC チャンネルにいたり、日常的に Rails の ChangeLog を見ていると思うので必要が無いとは思いますが、今後の公開版がどういった機能を備えるのかを把握するのには役に立つと思いますし、自分自身も更新を追うのにもちょうど良いと思うので、公式ブログの更新に合わせてこちらでも軽く翻訳を流していこうと思います。

 というわけで、早速。

開発版 Ruby on Rails の最新情報 (2008年6月20日)

 グレッグ・ポーラック (”Gregg Pollack,” Rails Envy Podcast) が一週間ほど前に言った様に、一週間前後で更新しているこの開発版 Rails の記事を今後も続けようと思います。Ruby on Rails の公式ブログでは初めての投稿なので、まずは少し自己紹介をさせてください。

 Living on the Edge (”先を行くこと”) とは、Rails Envy のグレッグ・ポーラックにそそのかされて、2007年12月から私が週刊で投稿していた記事のことです。というのも、以前は私自身も活発に Rails にコントリビュートしていたので、たいしたことではありませんでした。嬉しいことに、グレッグとジェイソン (”Jason Seifer,” Rails Envy)週に一度のポッドキャストでは、紹介もされました。

 これからは、この公式ブログでの更新になります。皆さんのご期待に添える様に有益な記事を書こうとを思います。今までは小さな個人的なブログだったので、それほどたいした価値もなかったかもしれませんが、ここでは話が違い、訪問者の量が違います。何か提案や批評がありましたらコメント欄にお気兼ねなく投稿してください。

 本題ですが、Rails 2.1 が公開されてからの過去二週間で、既にたくさんに新しい機能が Rails に実装され、API の変更や、パフォーマンス改善がされました。それらの投稿をまとめて大きな一つの投稿にする変わりに、新機能と API の変更という投稿と、パフォーマンス改善という投稿の二つに分けたいと思います。まずは、新機能と API の変更から。

 小規模な API 変更

 まずは小規模な API の変更から見てみましょう。

 ヘルパーメソッドの link_to が、非常に長いアンカーテキストを渡す場合などの為に、以下の様に、ブロック引数を受け取る様になりました。

<% link_to(@profile) do %>
  <strong><%= @profile.name %></strong> -
  <span>Status: <%= @profile.status %></span>
<% end %>

同じ機能をする以下のコードより綺麗かもしれません。

<%= link_to "#{@profile.name} -- Status: #{@profile.status}", @profile %>

prototype.js で有名なサム・ステファンソン (”Sam Stephenson”)と、デビッド=ハイネマイヤー・ハンソン (”David Heinemeier Hansson”) が実装してくれました。

コミット内容は GitHub から閲覧できます。

 ActiveRecord::Base#merge_conditions が公開メソッドに

 ジェーミー・キャンパー (”Jeremy Kamper”) が、ActiveRecord::Base#merge_conditions メソッドを公開メソッドにしてくれました。

これは、何らかの理由で複数のソースに条件があるときや、やはり何らかの理由で複数の条件をまとめる必要がある場合に便利です。

Post.merge_conditions(
  {:title => 'Lucky ☆ Star'},
  ['rating IN (?)', 1..5]
)
=> "(`posts`.`title` = 'Lucky ☆ Star') AND (rating IN (1,2,3,4,5))"

ただ、SQL のブール式 OR ではなく、AND を使って結合されることに気をつけてください。

コミット内容は GitHub から閲覧できます。

 関連付けの :validate オプション

 関連付けマクロが以下の様に :validation マクロを受け取る様になりました。

class Anime > ActiveRecord::Base
  has_many :characters, :validate => true
end

この様にすると、:validates_associated の様に、Anime モデルが保存される際、関連付けられた characters が正規化されます。初期値は false で、Rails 2.1 からの挙動の変化はありませんから、気にしなくても大丈夫です。

この変更と合わせて、難しいバグを直してくれたジャン・ド・ポールテル (”Jan De Poorter”) とプラティック・ネイク (”Pratik Naik”) に感謝。

コミット内容は GitHub から閲覧できます。バグのチケットはこちら。

 ハンソンさんが ActiveSupport::StringInquirer という以下の様なことを可能にする String のサブクラスを実装してくれました。

s = ActiveSupport::StringInquirer.new('awesome')
=> "awesome"
s.awesome?
=> true
s.sucks?
=> false

利用方法としては、既に Rails.envStringInquirer にされているので、現在の実行環境を Rails.env.development? や、Rails.env.production? といった方法で確認することが考えられます。

コミット内容は GitHub から閲覧できます。

コア拡張 Object#present? と Enumerable#many?

 ハンソンさんは、他にもコードの可読性を高めるコア拡張も実装してくれました。一つは Object#present? メソッドで、実機能は !Object#blank? です。

[].present?
=> false
[1, 2].present?
=> true
"".present?
=> false
"i'm here".present?
=> true

enumerable.size > 1 と同じ機能を果たす、Enumerable#many? メソッドも実装してくれました。

[].many?
=> false
[:just_me].many?
=> false
[:just_me, 'my_friend'].many?
=> true

Object#present?Enumerable#many? コミット内容は GitHub から閲覧できます。

 テスト用の宣言的ブロック文法

 ハンソンさんは、ジェイ・フィールズ (”Jay Fields”) に感銘を受け、以下の様な糖衣構文を追加してくれました。これにより、Test::Unit を使ったテストで、以下の様にブロック構造で記述ができる様になりました。

test "an anime should be invalid if any of its characters are invalid" do
  # Your usual test code here.
end

私自身は、Rails にパッチをアップロードする時以外は、めったに Test::Unit を使わず RSpec を利用していますが、この構造は確実に可読性を高めます。

コミット内容は GitHub から閲覧できます。

 パフォーマンステスト

 近頃 Rails の最適化とパフォーマンス改善に力を注いでいるキャンパーさんが、新しい結合テスト、パフォーマンステストを実装してくれました。

また、パフォーマンステストのスケルトンを生成してくれるジェネレーターも、ネイクさんによって実装されました。以下のコードで生成できます。

script/generate performance_test LoginStories

これらのパフォーマンステストを実行するには、まだ公開されていない ruby-prof のバージョン 0.6.1 以上が必要ですが、開発版がリポジトリからチェックアウトして gem を自分でインストールすることができます。今のところ、キャンパーさんのフォークした ruby-prof がおすすめです。ruby-prof 0.6.1 では、Test::Unit を使ってプロファイルテストを書けるところですが…。

先に進みましょう。試しに、ユーザー操作の仮説テスト (”Story Test”) に合わせてパフォーマンステストをしたいコントローラーに対していくつかのリクエストを行うテストを書き、実行すると、以下の様な実行結果が表示されます。また、/tmp/performance には、ruby-profile の出力が書き出されます。

> ruby performance/login_stories_test.rb
Loaded suite performance/login_stories_test
Started
LoginStoriesTest#test_homepage (32 ms warmup)
        process_time: 11 ms
              memory: unsupported
             objects: unsupported
.
Finished in 0.870842 seconds.

memoryobjects は未対応 (”unsupported”) となっていますが、これは私が、Ruby のインタープリターにパッチを当てていない為です。メモリープロファイリングと、ガベージコレクションプロファイリングを有効にするには、パッチを当てないといけないのです。この辺りはあまり詳しくないので詳しい情報を伝えられませんが、幸いにも詳しい方がこちらでメモリープロファイリング用のパッチに関する詳細を伝えてくれています。

コミット内容は GitHub から閲覧できます。

 あとがき

 Rails 2.1 から今までの新機能と API の変更点はこんなところです。パフォーマンス改善とについては次の投稿で紹介します。また、今回は、開発版に部分的にマージされた Rack への対応をあえて取り上げませんでした。

もし、何か間違えがあったり改善すべき点がありましたら、コメント欄でご指摘ください。Ruby インタープリターをメモリープロファイリングに対応させるパッチに関する情報は特に大歓迎です。取り上げていないものは、それほど重要でないと私が判断したものですが、そうでない場合もまたコメント欄でご指摘ください。

Ruby on Rails 公式ブログの記事