トップ «前の日記(2005-02-12) 最新 次の日記(2005-02-17)» 編集

活動日誌


2005-02-14

Rake

Rake というものがあります。 Ruby で記述できる make みたいなものだそうで、

 task :default => [:test]

 task :test do
   ruby "test/unittest.rb"
 end

といった感じに書けるそうです。

なかなか面白そうだと思ったので、ちょっと触ってみようと思います。

あまり推敲していませんが、doc/rakefile.doc を訳してみたので掲載します。

なお、Rake は MITライセンスです。

Rakefile フォーマット

まず、Rakefile のための特別なフォーマットは存在しません。 Rakefile は実行可能な Ruby のコードを含んでいます。 Ruby スクリプトとして合法な記述は全て、Rakefile でも許されています。

Rakefile のための特別な文法が存在しないことを理解したので、 Rakefile で使われる規約で、普通の Ruby プログラムではあまり見かけないも のがあります。 Rakefile はタスクやアクションを指定するために作られているので、 使われているイディオムはこの作業をサポートするためにデザインされています。

さて、Rakefile の構成はどうなっているのでしょうか。

タスク

タスクは、Rakefile 中での作業の主要な単位です。 タスクは名前(大抵はシンボルか文字列として与えられます)、 必要条件のリスト(シンボルまたは文字列として与えられます)、 アクションのリスト(ブロックとして与えられます)を 持ちます。

単純なタスク

タスクは、+task+ メソッドを用いることで宣言されます。 +task+ メソッドは、タスクの名前を一つパラメータとして取ります。

 task :name
必要条件を伴ったタスク

全ての必要条件は、名前と矢印(=>)に続く [ ] で囲まれたリストによって 与えられます。

 task :name => [:prereq1, :prereq2]

<b>注:<b> この文法は少し奇妙に見えるかもしれませんが、Ruby では合法です。 キーが :name で、その値が必要条件のリストであるようなハッシュを生成して います。 これは、次のように書くのと等価です。

 hash = Hash.new
 hash[:name] = [:prereq1, :prereq2]
 task(hash)
アクションを伴ったタスク

タクションは、+task+ メソッドにブロックを渡すことによって定義されます。 ブロックの中には、任意の Ruby コードを置くことができます。 ブロックでは、ブロック引数を通じてタスクオブジェクトを参照することができ ます。

 task :name => [:prereq1, :prereq2] do |t|
   # actions (may reference t)
 end
複数の定義

タスクは、複数回定義することができます。 それぞれの指定によって、既存の定義に必要条件とアクションが追加されます。 これによって、ある rakefile でアクションを指定し、 (おそらく別ファイルに生成された)他の rakefile で依存関係を指定すること ができるようになります。

例えば、次の記述は上に出てきた単一のタスク指定と等価です。

 task :name
 task :name => [:prereq1]
 task :name => [:prereq2]
 task :name do |t|
   # actions
 end

ファイルタスク

あるタスクは、一つまたは複数のファイルからファイルを生成するために用いら れます。 もし、生成するファイルが既に存在していた場合、このタスクはスキップされます。 ファイルタスクは、ファイルを生成するタスクを指定するために用いられます。

ファイルタスクは、(+task+ メソッドの代わりに) +file+ メソッドによって宣 言されます。 さらに、ファイルタスクに名前を付けるときには大抵の場合、シンボルよりも文 字列が使われます。

次のファイルタスクは、2つのオブジェクトファイル <tt>a.o</tt> と <tt>b.o</tt> が与えられた 実行可能プログラム +prog+ を生成します。 <tt>a.o</tt> および <tt>b.o</tt> を生成するタスクは示されていません。

 file "prog" => ["a.o", "b.o"] do |t|
   sh "cc -o #{t.name} #{t.prerequisites.join(' ')}"
 end

ディレクトリタスク

要求に応じてディレクトリを作成するのが必要であるのは一般的です。 +directory+ メソッドは、ディレクトリを作成する FileTask を作成するための 簡単な方法です。 例えば、次の宣言

 directory "testdata/examples/doc"

は、次と等価です。

 file "testdata"              do |t| mkdir t.name end
 file "testdata/examples"     do |t| mkdir t.name end
 file "testdata/examples/doc" do |t| mkdir t.name end

+directory+ メソッドには必要条件やアクションを指定できません。 しかし、これらは後から追加することができます。 例えば、次のようにやります。

 directory "testdata"
 file "testdata" => ["otherdata"]
 file "testdata" do
   cp Dir["standard_data/*.data"], "testdata"
 end

ルール

ファイルが必要条件として使われ、しかしそのファイルに対する ファイルタスクが存在しない場合、 Rake は Rakefile に記述されているルールを見て タスクを合成しようとします。

"mycode.o" タスクを呼び出そうとしているものの、 このファイルのためのタスクは定義されていないとしましょう。 しかし rakefile には、次のようなルールが記述されているとします。

 rule '.o' => ['.c'] do |t|
   sh "cc #{t.source} -c -o #{t.name}"
 end

このルールは、".o" で終わる任意のタスクを扱います。 これは、拡張子 ".c" のソースファイルを必要条件を持ちます。 もし Rake が "mycode.c" という名前のファイルを見つけることができた場合、 自動的に "mycode.c" から "mycode.o" をビルドするタスクが生成されます。

ソースファイル "mycode.c" が存在しなければならないことに注意してください。 Rake は(現状では)複数レベルのタスク合成を行おうとしません。

タスクがルールから生成された場合、マッチしたソースファイルに タスクの +source+ 属性が設定されます。 これによって、ソースファイルを参照するアクションを持ったルールを 書くことができます。

高度なルール

任意の正規表現がルールパターンとして使用できます。 加えて、ソースファイルの名前を求めるのに proc が使えます。 これにより、複雑なパターンとソースに対応できます。

次のルールは、前の例と等価です。

 rule( /\.o$/ => [
   proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') }
 ]) do |t|
   sh "cc #{t.source} -c -o #{t.name}"
 end

<b>注:</b> Ruby の_気まぐれな_文法のため、

  • rule*の最初の引数が正規表現の場合には ( ) が必要です。

次のルールは、Java ファイルに使われます。

 rule '.java' => [
   proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') }
 ] do |t|
   java_compile(t.source, t.name)
 end

<b>注:</b> +java_compile+ は Java コンパイラを呼び出す仮のメソッドです。

コメント

("#" で始まる)標準 Ruby コメントは、Ruby コードで合法な場所では、 タスクやルールのためのコメントも含めて どこでも使うことができます。 しかしながら、"-T" オプションでタスクの説明を出したい場合は、 +desc+ コマンドを使う必要があります。

例:

 desc "Create a distribution package"
 task :package => [ ... ] do ... end

"-T" オプション(省略しないのであれば "--tasks")は、定義されたコメントを持つ タスクのリストを出力します。 主要なタスクを記述するのに +desc+ を使えば、半自動的に Rake ファイルの概要を 生成することができます。

 traken$ rake -T
 (in /home/.../rake)
 rake clean            # Remove any temporary products.
 rake clobber          # Remove any generated file.
 rake clobber_rdoc     # Remove rdoc products
 rake contrib_test     # Run tests for contrib_test
 rake default          # Default Task
 rake install          # Install the application
 rake lines            # Count lines in the main rake file
 rake rdoc             # Build the rdoc HTML Files
 rake rerdoc           # Force a rebuild of the RDOC files
 rake test             # Run tests
 rake testall          # Run all test targets

"-T" オプションでは、説明を伴ったタスクのみが出力されます。 全てのタスクとその必要条件を得るには、"-P" (または "--prereqs")を使います。

その他

do/end 対 { }

Ruby においては、ブロックは +do+/+end+ のペアと { } のどちらでも指定することができますが、 タスクやルールのアクションを指定するときには +do+/+end+ を使うことを _強く_推奨します。 なぜならば、rakefile イディオムでは task/file/rule メソッドの括弧はよく 省略され、 { } を使った場合、あいまいさが起こるからです。

例えば、+object_files+ メソッドがプロジェクト中のオブジェクトファイルの リストを 返すとしましょう。 +object_files+ を、ルールの中の、アクションを { } で指定する必要条件とし て使ってみます。

 # DON'T DO THIS!
 file "prog" => object_files {
   # Actions are expected here (but it doesn't work)!
 }

{ } は +do+/+end+ より優先度が高く、 ブロックは +files+ メソッドではなく +object_files+ メソッドに 関連付けられるからです。

タスクを指定する適切な方法は、次の通りです。

 # THIS IS FINE
 file "prog" => object_files do
   # Actions go here
 end

原文 http://rake.rubyforge.org/files/doc/rakefile_rdoc.html


2005|02|03|04|05|06|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|03|04|05|06|10|
2008|04|10|
2009|10|
2010|05|08|
2012|01|02|03|
2014|01|
トップ «前の日記(2005-02-12) 最新 次の日記(2005-02-17)»