Module: Thor::Base

Included in:
Thor, Group
Defined in:
lib/thor/base.rb,
lib/thor/shell.rb,
lib/thor/base/class_methods.rb,
lib/thor/base/shared_concern.rb,
lib/thor/base/arguments_concern.rb,
lib/thor/base/common_class_options.rb

Overview

Declarations

Defined Under Namespace

Modules: ArgumentsConcern, ClassMethods, CommonClassOptions, SharedConcern

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.shellObject

Returns the shell used in all Thor classes. If you are in a Unix platform it will use a colored log, otherwise it will use a basic one without color.



11
12
13
14
15
16
17
18
19
# File 'lib/thor/shell.rb', line 11

def shell
  @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty?
    Thor::Shell.const_get(ENV["THOR_SHELL"])
  elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"]
    Thor::Shell::Basic
  else
    Thor::Shell::Color
  end
end

Instance Attribute Details

#argsObject

Attributes



114
115
116
# File 'lib/thor/base.rb', line 114

def args
  @args
end

#optionsObject

Attributes



114
115
116
# File 'lib/thor/base.rb', line 114

def options
  @options
end

#parent_optionsObject

Attributes



114
115
116
# File 'lib/thor/base.rb', line 114

def parent_options
  @parent_options
end

Class Method Details

.included(base) ⇒ void

This method returns an undefined value.

Hook called when Thor::Base is mixed in (Thor and Group).

Extends ‘base` with ClassMethods, and includes Invocation and Shell in `base` as well.

Parameters:

  • base (Module)

    Module (or Class) that included Thor::Base.



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/thor/base.rb', line 66

def self.included base
  base.extend ClassMethods
  base.send :include, Invocation
  base.send :include, Shell
  base.send :include, ArgumentsConcern
  base.send :include, SharedConcern
  
  base.no_commands {
    base.send :include, NRSER::Log::Mixin
  }
  
end

.register_klass_file(klass) ⇒ Object

Whenever a class inherits from Thor or Thor::Group, we should track the class and the file on Thor::Base. This is the method responsible for it.



100
101
102
103
104
105
106
107
108
# File 'lib/thor/base.rb', line 100

def self.register_klass_file(klass) #:nodoc:
  file = caller[1].match(/(.*):\d+/)[1]
  unless Thor::Base.subclasses.include?(klass)
    Thor::Base.subclasses << klass
  end

  file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
  file_subclasses << klass unless file_subclasses.include?(klass)
end

.subclass_filesObject

Returns the files where the subclasses are kept.

Returns

Hash[path<String> => Class]



93
94
95
# File 'lib/thor/base.rb', line 93

def self.subclass_files
  @subclass_files ||= Hash.new { |h, k| h[k] = [] }
end

.subclassesObject

Returns the classes that inherits from Thor or Thor::Group.

Returns

Array



84
85
86
# File 'lib/thor/base.rb', line 84

def self.subclasses
  @subclasses ||= []
end

Instance Method Details

#initialize(args = [], options_args_or_defaults = {}, config = {}) ⇒ Object

It receives arguments in an Array and two hashes, one for options and other for configuration.

Notice that it does not check if all required arguments were supplied. It should be done by the parser.

Parameters

args<Array>

An array of objects. The objects are applied to their respective accessors declared with argument.

options<Hash>

An options hash that will be available as self.options. The hash given is converted to a hash with indifferent access, magic predicates (options.skip?) and then frozen.

config<Hash>

Configuration for this Thor class.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/thor/base.rb', line 137

def initialize args = [], options_args_or_defaults = {}, config = {}
  # Before {#initialize} is called arguments have been split out into
  # either:
  # 
  # 1.  Positional `args` and args that need to be parsed for options.
  # 
  # 2.  Positional `args` and already parsed option values that we call
  #     "defaults".

  if options_args_or_defaults.is_a? Array
    # Case (1)
    # 
    # The start method splits inbound arguments at the first argument
    # that looks like an option (starts with - or --). It then calls
    # new, passing in the two halves of the arguments Array as the
    # first two parameters.
    # 
    # In this case the first Array stays as `args` and the second Array
    # gets assigned to `args_to_parse_for_options` to be parsed for
    # options:
    # 
    args_to_parse_for_options = options_args_or_defaults
    option_defaults = {}
  else
    # Case (2)
    # 
    # Handle the case where the class was explicitly instantiated
    # with pre-parsed options.
    # 
    args_to_parse_for_options = []
    option_defaults = options_args_or_defaults
  end

  logger.debug "#{ self.class.name }#initialize",
    args:                       args,
    options_args_or_defaults:   options_args_or_defaults,
    args_to_parse_for_options:  args_to_parse_for_options,
    option_defaults:            option_defaults

  # Let {Thor::Options} parse the options first, so it can remove
  # declared options from the array. This will leave us with
  # a list of arguments that weren't declared.

  # Hash of {Thor::Option} that we can parse from the CLI args
  # keyed by their {Thor::Option#name}.
  # 
  # @type [HashWithIndifferentAccess<String, Thor::Option>]
  # 
  options_to_parse_by_name = [
    # Add class-level options
    self.class.class_options,

    # Options passed in by {Thor.dispatch} for the command to be
    # invoked. May be `nil`, though I'm not totally sure when... in that
    # case those options won't be parsed.
    # 
    # This was
    # 
    #     config.delete( :command_options ),
    # 
    # though I can't figure out why. Specs still pass without it..
    # 
    config[:command_options],
  ].compact.reduce( HashWithIndifferentAccess.new, :merge! )

  stop_on_unknown = \
    self.class.stop_on_unknown_option? config[:current_command]
  
  disable_required_check = \
    self.class.disable_required_check? config[:current_command]

  logger.trace "Ready to create options",
    options_to_parse_by_name:     options_to_parse_by_name,
    option_defaults:              option_defaults,
    stop_on_unknown:              stop_on_unknown,
    disable_required_check:       disable_required_check,
    args:                         args,
    args_to_parse_for_options:    args_to_parse_for_options
  
  options_parser = Thor::Options.new \
    options_to_parse_by_name,
    option_defaults,
    stop_on_unknown,
    disable_required_check
  
  self.options = options_parser.parse args_to_parse_for_options
  
  if config[:class_options]
    self.options = config[:class_options].merge(options)
  end

  # If unknown options are disallowed, make sure that none of the
  # remaining arguments looks like an option.
  if self.class.check_unknown_options? config
    options_parser.check_unknown!
  end

  # Add the remaining arguments from the options parser to the
  # arguments passed in to initialize. Then remove any positional
  # arguments declared using #argument (this is primarily used
  # by Thor::Group). Tis will leave us with the remaining
  # positional arguments.
  to_parse  = args
  unless self.class.strict_args_position? config
    to_parse += options_parser.remaining
  end

  thor_args = Thor::Arguments.new [
    *self.class.class_arguments,
    *config[:current_command]&.arguments,
  ]

  # Set the arguments as instance variables.
  thor_args.parse( to_parse ).each { |k, v| __send__ "#{k}=", v }

  # Set whatever is left as args
  @args = thor_args.remaining
end

#on_run_error(error, command, args) ⇒ Object (protected)

Atli addition: An error handling hook that is called from Command#run when running a command raises an unhandled exception.

I don’t believe errors are recoverable at this point, but this hook allows the Thor subclass to respond to expected errors and gracefully inform the user.

It’s basically ‘goto fail` or whatever.

User overrides should always exit or re-raise the error.

The base implementation here simply re-raises.

Note that ArgumentError and NoMethodError are both rescued in Command#run and passed off to Thor’s relevant ‘.handle_*_error` methods, so you probably won’t be able to intercept any of those.

Generally, it’s best to use this to respond to custom, specific errors so you can easily bail out with a ‘raise` from anywhere in the application and still provide a properly formatted response and exit status to the user.

Errors that are only expected in a single command

Parameters:

  • error (Exception)

    The error the bubbled up to Command#run.

  • command (Thor::Command)

    The command instance that was running when the error occurred.

  • args (Array<String>)

    The arguments to the command that was running.



298
299
300
# File 'lib/thor/base.rb', line 298

def on_run_error error, command, args
  raise error
end

#on_run_success(result, command, args) ⇒ Object (protected)

Hook for processing values return by command methods. So you can format it or print it or whatever.

This implementation just returns the result per the specs.

Parameters:

  • result (Object)

    Whatever the command returned.

  • command (Thor::Command)

    The command instance that was running when the error occurred.

  • args (Array<String>)

    The arguments to the command that was running.

Returns:

  • (Object)

    The ‘result`.



320
321
322
# File 'lib/thor/base.rb', line 320

def on_run_success result, command, args
  result
end