The alias_method_chain of Rake - Override Rake Task
Rake is cool. It is built so that multiple tasks with the same name run in a reverse defined series. This is great, but sometimes you want to override a task with your own behavior and conditionally call the earlier task. Especially if that task is defined deep somewhere else, like in a rails gem. I have had to solve this problem before in Rake. Awhile back I hacked something up that would totally trump a predefined rake task and allow you to replace it with a new one. Lately while working on the SQL Server adapter, I had a need to method chain some core rails :db namespaced tasks. So once again I googled others work and again resorted to hacking Rake. Below is what I was left with.
Rake::TaskManager.class_eval do
def alias_task(fq_name)
new_name = "#{fq_name}:original"
@tasks[new_name] = @tasks.delete(fq_name)
end
end
def alias_task(fq_name)
Rake.application.alias_task(fq_name)
end
def override_task(*args, &block)
name, params, deps = Rake.application.resolve_args(args.dup)
fq_name = Rake.application.instance_variable_get(:@scope).dup.push(name).join(':')
alias_task(fq_name)
Rake::Task.define_task(*args, &block)
end
It's easy to use, just require it in your Rakefile. In the example below, I was able to programmatically method chain the core rails db:test:purge and only call the original if I needed to. Very cool!
namespace :db do
namespace :test do
override_task :purge => :environment do
...
# To invoke the original task add ":original" to its name
Rake::Task["db:test:purge:original"].execute
...
end
end
end
Lastly, thanks to Eugene Bolshakov, John Wood, and Mark Foster whom have tackled this rake problem before. My version above was based on their work, but correctly works with namespaces which was critical for my needs.