注意Rake Task中invoke方法跟execute方法的不同

March 2014 · 1 minute read

平时如果跟Rake Task有过接触的同学都会知道,当我们需要在一个Task里边调用另一个Task的时候,我们可以使用Rake::Task['task_name'].invoke的方式。但是在今天的实践中,才知道Rake::Task#invoke在默认情况下在整个运行过程中将只会被调用一次而已。话不多说,动手演示:

准备一个say hello的task,代码:

# lib/tasks/demo.rake
namespace :demo do
  desc "Print 'Hello' string"
  task :say_hello do
    puts "Hello, World!"
  end
end

接下来在命令行中执行rake task:

$ rake demo:say_hello
=> Hello, World!

假设我们一个循环,需要调用上边的task共5次,那么我们可能会这么写:

namespace :demo do
  # ....

  desc "Print 'Hello, World!' five times"
  task :say_five_hello do
    5.times do
      Rake::Task['demo:say_hello'].invoke
    end
  end
end

Ok, 让我们尝试着运行这个say_five_hello的task,是不是真的会打印5次’Hello, World!‘呢?

$ rake demo:say_five_hello
=> Hello, World!

结果就是,’Hello, World!‘只打印了一次,也就是说,我们的Rake::Task['demo:say_hello']只被运行了一次。

经过搜索,从StackOverflow找到了这个问题的相关描述,详见:How do I execute Rake tasks with arguments multiple times?

按照答案中的描述,我们有两种修改方案。第一种就是将上述代码进行修改:

namespace :demo do
  # ...

  desc "Print 'Hello, World!' five times"
  task :say_five_hello do
    5.times do
      Rake::Task['demo:say_hello'].execute
    end
  end
end

再次运行,这次总算得到期待结果了:

$ rake demo:say_five_hello
=> Hello, World!
   Hello, World!
   Hello, World!
   Hello, World!
   Hello, World!

而第二种方法则会稍微麻烦一点:

namespace :demo do
  # ...

  desc "Print 'Hello, World!' five times"
  task :say_five_hello do
    5.times do
      Rake::Task['demo:say_hello'].reenable
      Rake::Task['demo:say_hello'].invoke
    end
  end
end

再次执行rake task, 同样能够得到预期结果:

$ rake demo:say_five_hello
=> Hello, World!
   Hello, World!
   Hello, World!
   Hello, World!
   Hello, World!

未完待续

针对重复调用的行为上的不同只是invoke以及execute方法之间的一个基本差异而已,那第一种方案跟第二种方案的差异又有什么不同?在带参数的情况下,又该如何考虑两个方法之间的差异?

Rake::Task source code