Почему Rake не может последовательно вызывать несколько задач?

У меня есть задача Rake, которую я упростил ниже. Я использую Ruby 1.9 для Windows.

Возможно, вы хотели бы угадать результат вызова задачи Rake "list_all_levels" ниже? Это должно быть:

"Hello level 1"
"Hello level 2"
"Hello level 3"

Но по неизвестным мне причинам он печатает только "Hello level 1", а затем останавливается.

То есть он всегда вызывает только первую задачу. Если я изменил первую строку, чтобы передать аргумент "42", он напечатает "Привет, уровень 42", а затем остановится.

Мне интересно, почему он не вызывает задачу 3 раза и печатает все 3 строки? И есть ли способ заставить его работать так, как я ожидал бы?

task :list_all_levels => [] do
    Rake::Task[:list].invoke 1
    Rake::Task[:list].invoke 2
    Rake::Task[:list].invoke 3
end

task :list, [:level] => [] do |t, args|
    puts "Hello level #{args.level}"
end

Ответ 1

Проблема заключается в том, что invoke только вызывает задачу, если это необходимо. Выполнение rake --trace показывает:

(in /tmp/ruby)
** Invoke default (first_time)
** Execute default
** Invoke list (first_time)
** Execute list
Hello level 1
** Invoke list 
** Invoke list 

Итак, вы можете увидеть, как он пытается вызвать задачу :list еще два раза. Но одно можно сделать, чтобы изменить тело основной задачи на:

task :default => [] do
    Rake::Task[:list].invoke 1
    Rake::Task[:list].reenable
    Rake::Task[:list].invoke 2
    Rake::Task[:list].reenable
    Rake::Task[:list].invoke 3
end

то задача :list требуется снова, и она корректно выводит все 3 оператора.

Более чистый способ сделать это - использовать execute, а не invoke:

task :default => [] do
    Rake::Task[:list].execute 1
    Rake::Task[:list].execute 2
    Rake::Task[:list].execute 3
end

task :list, [:level] => [] do |t, args|
    puts "Hello level #{args}"
end

Это изменяет ваш оператор puts для использования только args, а не args.level по какой-либо причине. Существуют и другие предостережения с использованием execute over invoke, описанного в ссылке выше.

Ответ 2

Вам нужно снова включить задачу перед новым исполнением, для этого вам просто нужно выполнить метод, который можно повторно использовать. Как сказал Марк Рушаков.

Rake::Task[:list].reenable