module Thor::Invocation

def self.included(base) #:nodoc:

:nodoc:
def self.included(base) #:nodoc:
  base.extend ClassMethods
end

def _initialize_klass_with_initializer(object, args, opts, config) #:nodoc:

:nodoc:

Initialize klass using values stored in the @_initializer.
def _initialize_klass_with_initializer(object, args, opts, config) #:nodoc:
  if object.is_a?(Class)
    klass = object
    stored_args, stored_opts, stored_config = @_initializer
    args ||= stored_args.dup
    opts ||= stored_opts.dup
    config ||= {}
    config = stored_config.merge(_shared_configuration).merge!(config)
    [ klass, klass.new(args, opts, config) ]
  else
    [ object.class, object ]
  end
end

def _prepare_for_invocation(name, sent_task=nil) #:nodoc:

:nodoc:

given or even a Thor::Task object.
take into account that a just a task name from the current class was
Prepare for invocation in the instance level. In this case, we have to
def _prepare_for_invocation(name, sent_task=nil) #:nodoc:
  if name.is_a?(Thor::Task)
    task = name
  elsif task = self.class.all_tasks[name.to_s]
    object = self
  else
    object, task = self.class.prepare_for_invocation(nil, name)
    task ||= sent_task
  end
  # If the object was not set, use self and use the name as task.
  object, task = self, name unless object
  return object, _validate_task(object, task)
end

def _shared_configuration #:nodoc:

:nodoc:

Configuration values that are shared between invocations.
def _shared_configuration #:nodoc:
  { :invocations => @_invocations }
end

def _validate_task(object, task) #:nodoc:

:nodoc:

for it.
Check if the object given is a Thor class object and get a task object
def _validate_task(object, task) #:nodoc:
  klass = object.is_a?(Class) ? object : object.class
  raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
  task ||= klass.default_task if klass <= Thor
  task = klass.all_tasks[task.to_s] || Task.dynamic(task) if task && !task.is_a?(Thor::Task)
  task
end

def initialize(args=[], options={}, config={}, &block) #:nodoc:

:nodoc:

Make initializer aware of invocations and the initializer proc.
def initialize(args=[], options={}, config={}, &block) #:nodoc:
  @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] }
  @_initializer = [ args, options, config ]
  super
end

def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil)


invoke Rspec::RR, [], :style => :foo

Besides giving an instance, you can also give a class to invoke:

invoke "rspec:rr", [], :style => :foo

have to do that explicitely:
If you want Rspec::RR to be initialized with its own set of options, you

that it's going to use.
is invoked all options are parsed again, so RR can extract only the options
Since it's not rspec concern to parse mock framework options, when RR

end
class_option :style, :type => :string, :default => :mock
class Rspec::RR < Thor::Group

own options:
As you noticed, it invokes the given mock framework, which might have its

end
end
invoke "rspec:#{options[:mock_framework]}"
def invoke_mock_framework

class_option :mock_framework, :type => :string, :default => :rr
class Rspec < Thor::Group

some rspec tasks:
supplied to B. This allows lazy parse of options. Let's suppose you have
When class A invokes class B, all arguments used on A initialization are

if it's invoked later by "bar" method.
In the example above, invoking "foo" will invoke "b:hello" just once, even
By using an invocation system you ensure that a task is invoked only once.

which belongs to the same class and "hello" which belongs to the class B.
You can notice that the method "foo" above invokes two tasks: "bar",

end
end
puts "hello #{name}"
def hello(name)
class B < Thor

end
end
invoke "b:hello", ["José"]
def bar

end
invoke "b:hello", ["José"]
invoke :bar
def foo
class A < Thor

==== Examples

initialize the invoker are used to initialize the invoked.
the task to be invoked, if none is given, the same values used to
You can also supply the arguments, options and configuration values for

cannot be guessed by name, it can also be supplied as second argument.
"namespace:task"), a Thor::Task, a Class or a Thor instance. If the task
Receives a name and invokes it. The name can be a string (either "task" or
def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil)
  task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array)
  args, opts, config = nil, args, opts if args.is_a?(Hash)
  object, task    = _prepare_for_invocation(name, task)
  klass, instance = _initialize_klass_with_initializer(object, args, opts, config)
  method_args = []
  current = @_invocations[klass]
  iterator = proc do |_, task|
    unless current.include?(task.name)
      current << task.name
      task.run(instance, method_args)
    end
  end
  if task
    args ||= []
    method_args = args[Range.new(klass.arguments.size, -1)] || []
    iterator.call(nil, task)
  else
    klass.all_tasks.map(&iterator)
  end
end