Class: Thor::Group

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/thor/group.rb

Overview

Thor has a special class called Thor::Group. The main difference to Thor class is that it invokes all commands at once. It also include some methods that allows invocations to be done at the class method, which are not available to Thor commands.

Instance Attribute Summary

Attributes included from Base

#args, #options, #parent_options

Class Method Summary collapse

Methods included from Base

included, #initialize, register_klass_file, subclass_files, subclasses

Class Method Details

.class_options_help(shell, groups = {}) ⇒ Object

Overwrite class options help to allow invoked generators options to be shown recursively when invoking a generator.



161
162
163
164
165
166
# File 'lib/thor/group.rb', line 161

def class_options_help(shell, groups = {}) #:nodoc:
  get_options_from_invocations(groups, class_options) do |klass|
    klass.send(:get_options_from_invocations, groups, class_options)
  end
  super(shell, groups)
end

.desc(description = nil) ⇒ Object

The description for this Thor::Group. If none is provided, but a source root exists, tries to find the USAGE one folder above it, otherwise searches in the superclass.

Parameters

description<String>

The description for this Thor::Group.



16
17
18
19
20
21
22
# File 'lib/thor/group.rb', line 16

def desc(description = nil)
  if description
    @desc = description
  else
    @desc ||= from_superclass(:desc, nil)
  end
end

.get_options_from_invocations(group_options, base_options) ⇒ Object

Get invocations array and merge options from invocations. Those options are added to group_options hash. Options that already exists in base_options are not added twice.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/thor/group.rb', line 172

def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
  invocations.each do |name, from_option|
    value = if from_option
      option = class_options[name]
      option.type == :boolean ? name : option.default
    else
      name
    end
    next unless value

    klass, _ = prepare_for_invocation(name, value)
    next unless klass && klass.respond_to?(:class_options)

    value = value.to_s
    human_name = value.respond_to?(:classify) ? value.classify : value

    group_options[human_name] ||= []
    group_options[human_name] += klass.class_options.values.select do |class_option|
      base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
      !group_options.values.flatten.any? { |i| i.name == class_option.name }
    end

    yield klass if block_given?
  end
end

.handle_argument_error(command, error, args, arity) ⇒ Object

:nodoc:



207
208
209
210
211
212
# File 'lib/thor/group.rb', line 207

def handle_argument_error(command, error, args, arity) #:nodoc:
  msg = "#{basename} #{command.name} takes #{arity} argument"
  msg << "s" if arity > 1
  msg << ", but it should not."
  fail error, msg
end

.help(shell) ⇒ Object

Prints help information.

Options

short

When true, shows only usage.



29
30
31
32
33
34
35
# File 'lib/thor/group.rb', line 29

def help(shell)
  shell.say "Usage:"
  shell.say "  #{banner}\n"
  shell.say
  class_options_help(shell)
  shell.say desc if desc
end

.invocation_blocksObject

Stores invocation blocks used on invoke_from_option.



45
46
47
# File 'lib/thor/group.rb', line 45

def invocation_blocks #:nodoc:
  @invocation_blocks ||= from_superclass(:invocation_blocks, {})
end

.invocationsObject

Stores invocations for this class merging with superclass values.



39
40
41
# File 'lib/thor/group.rb', line 39

def invocations #:nodoc:
  @invocations ||= from_superclass(:invocations, {})
end

.invoke(*names, &block) ⇒ Object

Invoke the given namespace or class given. It adds an instance method that will invoke the klass and command. You can give a block to configure how it will be invoked.

The namespace/class given will have its options showed on the help usage. Check invoke_from_option for more information.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/thor/group.rb', line 56

def invoke(*names, &block) # rubocop:disable MethodLength
  options = names.last.is_a?(Hash) ? names.pop : {}
  verbose = options.fetch(:verbose, true)

  names.each do |name|
    invocations[name] = false
    invocation_blocks[name] = block if block_given?

    class_eval <<-METHOD, __FILE__, __LINE__
      def _invoke_#{name.to_s.gsub(/\W/, "_")}
        klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})

        if klass
          say_status :invoke, #{name.inspect}, #{verbose.inspect}
          block = self.class.invocation_blocks[#{name.inspect}]
          _invoke_for_class_method klass, command, &block
        else
          say_status :error, %(#{name.inspect} [not found]), :red
        end
      end
    METHOD
  end
end

.invoke_from_option(*names, &block) ⇒ Object

Invoke a thor class based on the value supplied by the user to the given option named “name”. A class option must be created before this method is invoked for each name given.

Examples

class GemGenerator < Thor::Group
  class_option :test_framework, :type => :string
  invoke_from_option :test_framework
end

Boolean options

In some cases, you want to invoke a thor class if some option is true or false. This is automatically handled by invoke_from_option. Then the option name is used to invoke the generator.

Preparing for invocation

In some cases you want to customize how a specified hook is going to be invoked. You can do that by overwriting the class method prepare_for_invocation. The class method must necessarily return a klass and an optional command.

Custom invocations

You can also supply a block to customize how the option is going to be invoked. The block receives two parameters, an instance of the current class and the klass to be invoked.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/thor/group.rb', line 110

def invoke_from_option(*names, &block) # rubocop:disable MethodLength
  options = names.last.is_a?(Hash) ? names.pop : {}
  verbose = options.fetch(:verbose, :white)

  names.each do |name|
    unless class_options.key?(name)
      fail ArgumentError, "You have to define the option #{name.inspect} " <<
                           "before setting invoke_from_option."
    end

    invocations[name] = true
    invocation_blocks[name] = block if block_given?

    class_eval <<-METHOD, __FILE__, __LINE__
      def _invoke_from_option_#{name.to_s.gsub(/\W/, "_")}
        return unless options[#{name.inspect}]

        value = options[#{name.inspect}]
        value = #{name.inspect} if TrueClass === value
        klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)

        if klass
          say_status :invoke, value, #{verbose.inspect}
          block = self.class.invocation_blocks[#{name.inspect}]
          _invoke_for_class_method klass, command, &block
        else
          say_status :error, %(\#{value} [not found]), :red
        end
      end
    METHOD
  end
end

.printable_commandsObject Also known as: printable_tasks

Returns commands ready to be printed.



199
200
201
202
203
204
# File 'lib/thor/group.rb', line 199

def printable_commands(*)
  item = []
  item << banner
  item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "")
  [item]
end

.remove_invocation(*names) ⇒ Object

Remove a previously added invocation.

Examples

remove_invocation :test_framework


149
150
151
152
153
154
155
156
# File 'lib/thor/group.rb', line 149

def remove_invocation(*names)
  names.each do |name|
    remove_command(name)
    remove_class_option(name)
    invocations.delete(name)
    invocation_blocks.delete(name)
  end
end