require "set" module RakeTask CALLED = Set.new NAMESPACES = [] TASKS = Hash.new { |h, k| h[k] = Struct.new(:blocks, :deps).new([], []) } def self.call(name) return if CALLED.include?(name) raise "Unknown task: #{name.inspect}" unless TASKS.key?(name) CALLED << name (task = TASKS[name]).deps.each { |t| call(t) } task.blocks.each { |b| b[] } end def self.namespace(name, &block) NAMESPACES << name && yield ensure NAMESPACES.pop! end def self.task(spec, &block) name, deps = spec.entries[0] rescue name = spec name, deps = (NAMESPACES + [name.to_s]) * ":", Array(deps).map { |d| d.to_s } TASKS[name].blocks << block TASKS[name].deps |= deps end end RakeTask.module_eval do task :super do puts "Super" end task :super do puts "Super2" end task "duper" do puts "Duper" end task :awesome => :super do puts "Awesome" end task :cool => [:awesome, :duper] do puts "Cool" end %w(awesome cool).each { |t| RakeTask.call(t) } end