I paired with Yogi today on a few Rake tasks for our build. I mistakenly thought a Rake task could be overwritten by redefining it. That behavior may not be expected for build tasks, but it would be analogous to defining methods in Ruby:
class Person def first_name "Yogi" end def first_name "Dan" end end Person.new.first_name #=> "Dan"
For custom Rake tasks, you shouldn't need to modify them after the original definition. However, if you want to add behavior to some vendor tasks (such as those defined with Rails), this blog post will cover how to do that.
When defining a Rake Task twice, the new prerequisites are appended to the existing ones, and the block for the task is added to the previously defined behavior. Here is an example:
task(:x) { puts "x" } task(:y) { puts "y" } task(:z) { puts "z" } desc "First foo task" task :foo => :x do puts "first foo task" end desc "Second foo task" task :foo => [:y, :z] do puts "second foo task" end
Running rake :foo outputs:
$ rake foo x y z first foo task second foo task
As you can see, Rake executed the pre-requisites and actions for both task definitions. Rake also combines the task descriptions. Here is the output from rake --tasks (or rake -T):
$ rake -T rake foo # First foo task / Second foo task
Rake provides an easy mechanism for detecting if a task is already defined:
task :foo do end Rake::Task.task_defined?(:foo) #=> true Rake::Task.task_defined?(:bar) #=> false
Although a developer can add pre-requisites to an existing task by using the task method, it's not a good idea. A developer could leave a comment that he or she was simply adding pre-requisites, but code should be able to document itself. Before providing a superior alternative, here is an example of what I'm saying is bad:
# assume foo is an existing 'vendor' rake task: task :foo => [:add_prereq_1, :add_prereq_2]
Without the comment, the intention of adding pre-requisites to an existing task is not clear. However, using the enhance method makes the change much more intentional:
Rake::Task[:foo].enhance [:add_prereq_1, :add_prereq_2]
The enhance method can also add behavior that runs after the originally defined behavior.
Rake::Task["db:test:prepare"].enhance do Rake::Task["db:test:special_task_after_prepare"].invoke end
Invoking the db:test:prepare task will now execute the original pre-requisites, the original action, and then the added db:test:special_task_after_prepare task.
Modifying a vendor Rake task is not a good idea unless you really need to. A new developer coming into the project will not expect that well-known tasks are doing something different (and you're likely to forget that you modified a task later). You may want to consider making changes like these in a file named something like extensions.rake. If you modify a task, make the changes evident and intentional by using Rake::Task#enhance.