Rake Task の定義記法がよくわからなかったので調べた
Ruby も勉強しつつ Railsを触っています。Rake タスクの記述方法でよくわからない書き方に遭遇しました。
task products: :environment do
calculate_products
end
do~end
でタスク定義のブロックを渡していることはわかりますが、products: :environment
が理解できず。 products
というタスク名が定義され、ブロックが実行される前に :environment
という事前タスクを実行しておく という流れになるのはわかるのですが、なぜそういう処理になるのか、引数の渡し方がわかっていません。せっかくなので調べてみることにしました。
前提知識もとい TL;DR
- task メソッドは引数としてタスク名、パラメータ、依存タスク名を受け取れる
- Hash リテラルの
{:name => "value"}
と{name: "value"}
は同じである - メソッド呼び出しで、引数リストの最後が Hash リテラルの場合は
{}
を省略できる
特に最後のルールがわかっていなくて苦労しました。こちらの記事に助けられました、ありがとうございます。
task メソッド深堀り
よくわからなくて task メソッドの定義を見たら、
task(task_name)
task(task_name: dependencies)
task(task_name, arguments => dependencies)
Declare a basic task. The task_name is always the first argument. If the task name contains a “:” it is defined in that namespace. The dependencies may be a single task name or an Array of task names. The argument (a single name) or arguments (an Array of names) define the arguments provided to the task. The task, argument and dependency names may be either symbols or strings. A task with a single dependency:
task clobber: %w[clean] do
rm_rf "html"
end
A task with an argument and a dependency:
task :package, [:version] => :test do |t, args|
# ...
end
先頭の引数にタスク名がくることはわかりましたが、:
や =>
の存在がどういう意味なのかがわかっていません。Hash リテラルっぽいですが、Hash リテラルは
{name: "value"}
// であったり
{:name => "value"}
のように、{}
が必要なはずです。コンソールで打ってもエラーになるし。
irb(main):006:0> task_name: "abc"
Traceback (most recent call last):
SyntaxError ((irb):6: syntax error, unexpected ':', expecting end-of-input)
task_name: "abc"
よくわからないということで、task の実装まで見ていくことにしました。どうやら、末尾の依存関係があるかないかで引数をパースするメソッドを変えている模様。
def resolve_args_with_dependencies(args, hash) # :nodoc:
やはり引数として hash を受けているようです。ということは、特殊な受け取り方をして task
内部で Hash に変換しているか、メソッドにパラメータを渡すときに何かしらのルールがあるのかな?と考えました。調べているとドンピシャな記事が。
引数リストの最後がHashリテラルの場合は{}を省略できる。
これか…。Ruby文法は勉強中ですが、このあたりの糖衣構文は全然カバーできていません。助かりました。
仕掛けがわかればいろいろな書き方ができる
というわけで、仕組みわからなかった以下のtask呼び出しは、
task products: :environment do
calculate_products
end
- key が
:products
シンボル、 value が:environment
の Hash リテラルを渡している - これは task メソッド側で
task :t => [:d]
と認識される -
:products
がタスク名、:environment
が依存する事前タスクと解釈される
のような動きになっていることがわかりました。仕掛けがわかればこちらのものです。以下はすべて同じ解釈のされかたをされるはずです。
task products: :environment do
calculate_products
end
task :products => :environment do
calculate_products
end
task products: [:environment] do
calculate_products
end
勉強になりました。
Discussion