2007年11月25日日曜日

Rake ことはじめ

Rails アプリケーションを作っていると、
rake db:migrate 
というコマンドをよく叩きます。しかし、Rake についてよく理解していないので調査してみました。

Rake とは?

Rake は Ruby 版 makeです。

Rake でできること

  • メンバーのリストを取得して、Email を送る
  • 毎日のバッチ処理
  • 古いキャッシュを消去し生成
  • データベースやサブバージョンのバックアップ
  • データ操作のスクリプトを走らせる

タスクを登録する

ゆで卵を食べるために、以下の 3 つのタスクを考えてみます。
  • 卵を買う
  • 水を沸騰させる
  • ゆで卵をゆでる
これらのタスクを Rake ファイルを使って呼出してみます。
task :purchaseEggs do
puts 'Purchase eggs.'
end

task :boilWater do
puts 'Boil the water.'
end

task :makeBoiledEggs do
puts 'Make boiled eggs. They are delicious!'
end
このスクリプトを記述したファイルを Rakefile として保存して、これらのタスクをコマンドラインから呼出してみましょう。
# rake purchaseEgg
Purchase eggs.

# rake boilWater
Boil the water.

# rake makeBoiledEggs
Make boiled eggs.

タスクの依存関係の設定

卵を茹でるタスクには、次のような依存関係があります。
  • 水を沸騰させる前に卵を購入する
  • 卵を茹でる前に水を沸騰させておく
というわけで、卵を茹でるタスクたちに依存関係を設定します。
task :purchaseEggs do
puts 'Purchase eggs.'
end

task :boilWater => :purchaseEggs do
puts 'Boil the water.'
end

task :makeBoiledEggs => :boilWater do
puts 'Make boiled eggs. They are delicious!'
end
このように、依存関係は、
タスク名=> '依存するタスク名' 
で指定します。それではコマンドラインからタスクを呼出してみます。
# rake purchaseEgg
Purchase eggs.

# rake boilWater
Purchase eggs.
Boil the water.

# rake makeBoiledEggs
Purchase eggs.
Boil the water.
Make boiled eggs. They are delicious!
依存関係を設定した今回の場合、卵を茹でるタスクの前に、卵を買うタスク、水を沸騰させるタスクを呼ぶことができました。

タスクの説明文

desc を使ってタスクの説明文をつけます。自分以外の人がタスクを発行する場合には説明文があった方が助かりますね。
desc 'This task will purchase eggs.'
task :purchaseEggs do
puts 'Purchase eggs.'
end

desc 'This task will boil the water.'
task :boilWater => :purchaseEggs do
puts 'Boil the water.'
end

desc 'This task will make my boiled eggs.'
task :makeBoiledEggs => :boilWater do
puts 'Make boiled eggs. They are delicious!'
end
desc の記述は 'rake -T' または 'rake --tasks' コマンドで確認することができます。
# rake --tasks
rake purchaseEggs # This task will Purchase eggs.
rake boilWater # This task will boil the water.
rake makeBoiledEggs # This task will make my boiled eggs.

Rake の名前空間を設定

タスクを沢山登録した後は名前空間を使ってカテゴライズしておくのが吉です。というわけで茹で卵のタスクにも名前空間を設定します。
namespace :boiledeggs do
desc 'This task will purchase eggs.'
task :purchaseEggs do
puts 'Purchase eggs.'
end

desc 'This task will boil the water.'
task :boilWater => :purchaseEggs do
puts 'Boil the water.'
end

desc 'This task will make my boiled eggs.'
task :makeBoiledEggs => :boilWater do
puts 'Make boiled eggs. They are delicious!'
end
end
先程と同じように rake--tasks コマンドを発行してみます。
# rake --tasks
rake boiledeggs:purchaseEggs # This task will Purchase eggs.
rake boiledeggs:boilWater # This task will boil the water.
rake boiledeggs:makeBoiledEggs # This task will make my boiled eggs.
このタスクを走らせるには、
# rake boiledeggs:makeBoiledEggs
となります。

Rails で Task

Ruby のタスクを見てきましたが、Rails アプリケーションでタスクを登録して実行するやり方も見ておきます。Rails APP のルートディレクトリで
# rake --tasks
とコマンドを発行させると既に沢山のタスクが登録されているのが分かります。自分でオリジナルのタスクを登録するには、#{RAILS_ROOT}/lib/tasks ディレクトリに 'foo.rake' と保存しておきます。
上記の例では、boiledeggs という名前空間をつけた茹で卵を作るタスク群を foo.rake いうファイル名で保存しておけば、以下のようにタスクを実行できます。
# rake boiledeggs:makeBoiledEggs
Purchase eggs.
Boil the water.
Make boiled eggs. They are delicious!

Rails 内のモデルを使うタスクを書く

Rails APP 内のモデルを使ってタスクを呼出すことができます。以下の例を見てください。
namespace :boiledeggs do
desc 'This task will purchase eggs.'
task :purchaseEggs do
puts 'Purchase eggs'
end

desc 'This task will boil the water.'
task :boilWater => :purchaseEggs do
puts 'Boil the water.'
end

desc 'This task will make my boiled eggs.'
task :makeBoiledEggs => [:boilWater,:environment] do
User.find(:all).each{|u|
puts "Emailg #{u.email}"
puts 'Make boiled eggs. They are delicious!'
# ここにメール送信の処理を書く
}
end
end
茹で卵を茹でたら、ユーザ一人一人にメールを送信しています。
上記のように、モデルにアクセスするには、'=> :environment' 宣言が必要です。
production の DB を使いたい場合は、
rake RAILS_ENV=production boiledeggs:makeBoiledEggs
と指定して実行します。
バッチ実行処理などの場合は以下のようにクーロン登録しておくと便利ですね。
0 0 * * * cd /path/to/railsapp; /usr/local/bin/rake RAILS_ENV=production boiledeggs:makeBoiledEggs

参考: 本記事では以下の記事にお世話になりました m(_ _)m。
File: rakefile.rdoc
活動日誌(2005-02-14)(上記の日本語訳)
Rails Envy: Ruby on Rails Rake Tutorial.
僕にもできた! Rake