Ruby

rakeタスク内で別のタスクを呼び出す

More than 1 year has passed since last update.

rakeタスク内で別のタスクを呼びたいなーと思い調べてみた。
Rake::Task#invokeRake::Task#executeの2通りの呼び出し方があるみたい。
実際に使ってみると引数の扱い方が違っていてハマったのでメモしておく。

参考:
http://stackoverflow.com/questions/577944/how-to-run-rake-tasks-from-within-rake-tasks

試しにこんなタスクを書いてみた

namespace :mytask do
  task :hello, [:person] do |t, args|
    puts "hello #{args.person}"
  end

  task :execute_hello_to_paty do |t, args|
    Rake::Task["mytask:hello"].execute("paty")
  end

  task :invoke_hello_to_paty do |t, args|
    Rake::Task["mytask:hello"].invoke("paty")
  end
end

引数の渡し方が違うため#invokeを使ってる方は期待通り動くが、#executeはエラーになる

$ bundle exec rake mytask:execute_hello_to_paty
rake aborted!
undefined method `person' for "paty":String

rake task内で使ってるargsはRake::TaskArgumentsのインタンスを想定していて、#invokeの場合は引数を良しなに加工してtaskを呼び出してくれる

rake-10.1.0/lib/rake/task.rb
159     def invoke(*args)
160       task_args = TaskArguments.new(arg_names, args)
161       invoke_with_call_chain(task_args, InvocationChain::EMPTY)
162     end

一方、#executeでは引数をそのままtaskに渡している

rake-10.1.0/lib/rake/task.rb
223     def execute(args=nil)
224       args ||= EMPTY_TASK_ARGS
....
232         case act.arity
233         when 1
234           act.call(self)
235         else
236           act.call(self, args)
237         end
238       end
239     end

なので、今回のような書き方で別taskを呼びたい場合、こんな感じで書くといける

  task :execute_hello_to_paty do |t, args|
    Rake::Task["mytask:hello"].execute(Rake::TaskArguments.new([:person], ["paty"])
  end

あまり綺麗じゃないと思う・・・。
#execute#invokeでは他にも挙動の違いがあるので、どちらを使うかは状況次第な感じ

#execute

  • 呼び出すタスクの依存タスクは実行しない

#invoke

  • 呼び出すタスクの依存タスクも実行する
  • 実行中は1度しか同じタスクを実行しない
  • 再実行したい場合はRake::Task["task_name"].reenableを実行する必要がある

詳しくは参考リンク先に色々と書いてあるため割愛です。