module Rake::TaskManager
def [](task_name, scopes=nil)
def [](task_name, scopes=nil) task_name = task_name.to_s self.lookup(task_name, scopes) or enhance_with_matching_rule(task_name) or synthesize_file_task(task_name) or fail "Don't know how to build task '#{task_name}'" end
def attempt_rule(task_name, extensions, block, level)
def attempt_rule(task_name, extensions, block, level) sources = make_sources(task_name, extensions) prereqs = sources.collect { |source| if File.exist?(source) || Rake::Task.task_defined?(source) source elsif parent = enhance_with_matching_rule(sources.first, level+1) parent.name else return nil end } task = FileTask.define_task({task_name => prereqs}, &block) task.sources = prereqs task end
def clear
def clear @tasks.clear @rules.clear end
def create_rule(*args, &block)
def create_rule(*args, &block) pattern, arg_names, deps = resolve_args(args) pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern @rules << [pattern, deps, block] end
def current_scope
Return the list of scope names currently active in the task
def current_scope @scope.dup end
def define_task(task_class, *args, &block)
def define_task(task_class, *args, &block) task_name, arg_names, deps = resolve_args(args) task_name = task_class.scope_name(@scope, task_name) deps = [deps] unless deps.respond_to?(:to_ary) deps = deps.collect {|d| d.to_s } task = intern(task_class, task_name) task.set_arg_names(arg_names) unless arg_names.empty? task.add_description(@last_description) @last_description = nil task.enhance(deps, &block) task end
def enhance_with_matching_rule(task_name, level=0)
source attribute of the task appropriately for the rule. Return
task with the prerequisites and actions from the rule. Set the
If a rule can be found that matches the task name, enhance the
def enhance_with_matching_rule(task_name, level=0) fail Rake::RuleRecursionOverflowError, "Rule Recursion Too Deep" if level >= 16 @rules.each do |pattern, extensions, block| if md = pattern.match(task_name) task = attempt_rule(task_name, extensions, block, level) return task if task end end nil rescue Rake::RuleRecursionOverflowError => ex ex.add_target(task_name) fail ex end
def generate_name
def generate_name @seed ||= 0 @seed += 1 "_anon_#{@seed}" end
def in_namespace(name)
Evaluate the block in a nested namespace named +name+. Create
def in_namespace(name) name ||= generate_name @scope.push(name) ns = NameSpace.new(self, @scope) yield(ns) ns ensure @scope.pop end
def initialize
def initialize super @tasks = Hash.new @rules = Array.new @scope = Array.new @last_description = nil end
def intern(task_class, task_name)
Lookup a task. Return an existing task if found, otherwise
def intern(task_class, task_name) @tasks[task_name.to_s] ||= task_class.new(task_name, self) end
def lookup(task_name, initial_scope=nil)
are recognized. If no scope argument is supplied, use the
synthesize file tasks or rules. Special scope names (e.g. '^')
This method performs straight lookups without trying to
Lookup a task, using scope and the scope hints in the task name.
def lookup(task_name, initial_scope=nil) initial_scope ||= @scope task_name = task_name.to_s if task_name =~ /^rake:/ scopes = [] task_name = task_name.sub(/^rake:/, '') elsif task_name =~ /^(\^+)/ scopes = initial_scope[0, initial_scope.size - $1.size] task_name = task_name.sub(/^(\^+)/, '') else scopes = initial_scope end lookup_in_scope(task_name, scopes) end
def lookup_in_scope(name, scope)
def lookup_in_scope(name, scope) n = scope.size while n >= 0 tn = (scope[0,n] + [name]).join(':') task = @tasks[tn] return task if task n -= 1 end nil end
def make_sources(task_name, extensions)
Make a list of sources from the list of file name extensions /
def make_sources(task_name, extensions) extensions.collect { |ext| case ext when /%/ task_name.pathmap(ext) when %r{/} ext when /^\./ task_name.ext(ext) when String ext when Proc if ext.arity == 1 ext.call(task_name) else ext.call end else fail "Don't know how to handle rule dependent: #{ext.inspect}" end }.flatten end
def resolve_args(args)
Resolve the arguments for a task/rule. Returns a triplet of
def resolve_args(args) task_name = args.shift arg_names = args #.map { |a| a.to_sym } needs = [] if task_name.is_a?(Hash) hash = task_name task_name = hash.keys[0] needs = hash[task_name] end if arg_names.last.is_a?(Hash) hash = arg_names.pop needs = hash[:needs] fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1 end needs = [needs] unless needs.respond_to?(:to_ary) [task_name, arg_names, needs] end
def synthesize_file_task(task_name)
def synthesize_file_task(task_name) return nil unless File.exist?(task_name) define_task(Rake::FileTask, task_name) end
def tasks
def tasks @tasks.values.sort_by { |t| t.name } end