Module: Thor::Invocation

Defined in:
lib/thor/invocation.rb

Overview

Note:

Included when Base is included - and that’s the only place it’s included from what I can find, so this stuff just ends up in Thor and Group.

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



8
9
10
# File 'lib/thor/invocation.rb', line 8

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

Instance Method Details

#_parse_initialization_options(args, opts, config) ⇒ Object (protected)

Initialize klass using values stored in the @_initializer.



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/thor/invocation.rb', line 170

def _parse_initialization_options(args, opts, config) #:nodoc:
  stored_args, stored_opts, stored_config = @_initializer

  args ||= stored_args.dup
  opts ||= stored_opts.dup

  config ||= {}
  config = stored_config.merge(_shared_configuration).merge!(config)

  [args, opts, config]
end

#_retrieve_class_and_command(name, sent_command = nil) ⇒ Object (protected) Also known as: _retrieve_class_and_task

This method simply retrieves the class and command to be invoked. If the name is nil or the given name is a command in the current class, use the given name and return self as class. Otherwise, call prepare_for_invocation in the current class.



157
158
159
160
161
162
163
164
165
166
# File 'lib/thor/invocation.rb', line 157

def _retrieve_class_and_command(name, sent_command = nil) #:nodoc:
  if name.nil?
    [self.class, nil]
  elsif self.class.all_commands[name.to_s]
    [self.class, name.to_s]
  else
    klass, command = self.class.prepare_for_invocation(nil, name)
    [klass, command || sent_command]
  end
end

#_shared_configurationObject (protected)

Configuration values that are shared between invocations.



149
150
151
# File 'lib/thor/invocation.rb', line 149

def _shared_configuration #:nodoc:
  {:invocations => @_invocations}
end

#current_command_chainObject

Make the current command chain accessible with in a Thor-(sub)command



34
35
36
# File 'lib/thor/invocation.rb', line 34

def current_command_chain
  @_invocations.values.flatten.map(&:to_sym)
end

#initialize(args = [], options = {}, config = {}, &block) ⇒ Object

Make initializer aware of invocations and the initialization args.



27
28
29
30
31
# File 'lib/thor/invocation.rb', line 27

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

#invoke(name = nil, *args) ⇒ Object

Receives a name and invokes it. The name can be a string (either “command” or “namespace:command”), a Thor::Command, a Class or a Thor instance. If the command cannot be guessed by name, it can also be supplied as second argument.

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

When no name is given, it will invoke the default command of the current class.

Examples

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

  def bar
    invoke "b:hello", ["Erik"]
  end
end

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

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

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

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

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

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

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

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

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

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

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

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

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


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/thor/invocation.rb', line 106

def invoke(name = nil, *args)
  if name.nil?
    warn "[Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
    return invoke_all
  end

  args.unshift(nil) if args.first.is_a?(Array) || args.first.nil?
  command, args, opts, config = args

  klass, command = _retrieve_class_and_command(name, command)
  raise "Missing Thor class for invoke #{name}" unless klass
  raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base

  args, opts, config = _parse_initialization_options(args, opts, config)
  klass.send(:dispatch, command, args, opts, config) do |instance|
    instance.parent_options = options
  end
end

#invoke_allObject

Invoke all commands for the current instance.



137
138
139
# File 'lib/thor/invocation.rb', line 137

def invoke_all #:nodoc:
  self.class.all_commands.map { |_, command| invoke_command(command) }
end

#invoke_command(command, *args) ⇒ Object Also known as: invoke_task

Invoke the given command if the given args.



126
127
128
129
130
131
132
133
# File 'lib/thor/invocation.rb', line 126

def invoke_command(command, *args) #:nodoc:
  current = @_invocations[self.class]

  unless current.include?(command.name)
    current << command.name
    command.run(self, *args)
  end
end

#invoke_with_padding(*args) ⇒ Object

Invokes using shell padding.



142
143
144
# File 'lib/thor/invocation.rb', line 142

def invoke_with_padding(*args)
  with_padding { invoke(*args) }
end