class Thor::Task
Constants
- FILE_REGEXP
Public Class Methods
# File lib/thor/command.rb, line 18 def initialize name:, description: nil, long_description: nil, usage: nil, examples: [], arguments: [], options: nil super \ name.to_s, description, long_description, usage, examples, arguments, options || {} end
Public Instance Methods
Returns the formatted usage by injecting given required arguments and required options into the given usage.
# File lib/thor/command.rb, line 163 def formatted_usage(klass, namespace = true, subcommand = false) logger.trace "Formatting usage", self: self, klass: klass, namespace: namespace, subcommand: subcommand, ancestor_name: ancestor_name if ancestor_name formatted = "#{ancestor_name} ".dup # add space elsif namespace namespace = klass.namespace formatted = "#{namespace.gsub(/^(default)/, '')}:".dup end formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand formatted ||= "".dup # Add usage with required arguments arguments = klass&.arguments( command: self ) || [] formatted << unless arguments.empty? usage.to_s.gsub(/^#{name}/) do |match| match << " " \ << arguments.map(&:usage).compact.join(" ") end else usage.to_s end # Add required options formatted << " #{required_options}" # Strip and go! formatted.strip end
The name formats we recognize for the command, in command completion resolution order.
@note
In reality, since input words have `-` replaced with `_` when finding their instances during execution,
@return [Hash<Symbol, String>]
Keys and values in order (and order matters when completing commands, first result takes priority): 1. `usage:` {#usage_name} 2. `method:` {#name}, which is the command's actual method name, and hence "underscored". 3. `dashed:` A dash-separated version of {#name}.
# File lib/thor/command.rb, line 231 def names_by_format @names_by_format ||= { usage: usage_name, method: name, dashed: name.dasherize, }.freeze end
Run a command by calling the actual method on the {Thor::Base} instance.
By default, a command invokes a method in the thor class. You can change this implementation to create custom commands.
@param [Thor::Base] instance
Thor class instance the command is being run for.
@param [Array<?>] args
Arguments for the command.
@return
The return value of the command method on `instance`.
@raise [Thor::InvocationError]
1. When we find a suitable method on `instance` to call, but it raised and {ArgumentError} **and** {#handle_argument_error?} returned `true`.
# File lib/thor/command.rb, line 64 def run instance, args = [] logger.debug "Command#run", name: self.name, args: args # raise "BAD!!!" unless args.include? '--' # Declaration for arity of the method, which is set in (2) below and # used when handling raised {ArgumentError} arity = nil # Method invocation switch - figure out how to make the method call to # `instance`, or error out. # # Cases: # # 1. Protect from calling private methods by error'ing out if {#name} # is the name of a private method of `instance`. # result = if private_method? instance instance.class.handle_no_command_error name # 2. The success case - if {#name} is a public method of `instance` # than call it with `args`. # elsif public_method? instance # Save the arity to use when handling {ArgumentError} below # # TODO Why does it fetch the {Method} *then* use {#__send__} instead # of just `#call` it? # arity = instance.method( name ).arity # Unless the method is a subcommand, remove any '--' separators # since we know we're done option parsin' unless subcommand? instance, name args = args.reject { |arg| arg == '--' } end # Do that call instance.__send__ name, *args # 3. If the {Thor} instance has a `#method_missing` defined in *itself* # (not any super class) than call that. # elsif local_method? instance, :method_missing instance.__send__ :method_missing, name.to_sym, *args # 4. We got nothing... pass of to # {Thor::Base::ClassMethods.handle_no_command_error} # which will raise. # else instance.class.handle_no_command_error name end # Method invocation switch instance.__send__ :on_run_success, result, self, args rescue ArgumentError => error if handle_argument_error? instance, error, caller # NOTE I *believe* `arity` could still be `nil`, assuming that # (3) could raise {ArgumentError} and end up here. # # However... instance.class.handle_argument_error self, error, args, arity else raise error end rescue NoMethodError => error if handle_no_method_error? instance, error, caller instance.class.handle_no_command_error name else raise error end rescue Exception => error # NOTE Need to use `#__send__` because the instance may define a # command (method) `#send` - and one of the test fixtures **does**: # # //spec/fixtures/script.thor:100 # # That's why the Thor code above uses `#__send__`, and we need to # too. # instance.__send__ :on_run_error, error, self, args # We should not get here!!! # {Thor::Base#on_run_error} should exit or re-raise :( logger.error "#on_run_error failed to exit or re-raise", error: error # If you want something done right... raise error end
The command's name as depicted in it's {#usage} message.
We prefer this format when completing commands because it's how we depict the command to the user.
@see Thor::Completion
@see names_by_format
@return [String]
# File lib/thor/command.rb, line 210 def usage_name @usage_name ||= usage.shellsplit[0] end
Protected Instance Methods
# File lib/thor/command.rb, line 333 def handle_argument_error?(instance, error, caller) not_debugging?(instance) \ && ( error.message =~ /wrong number of arguments/ \ || error.message =~ /given \d*, expected \d*/ ) \ && begin saned = sans_backtrace(error.backtrace, caller) # Ruby 1.9 always include the called method in the backtrace saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9") end end
# File lib/thor/command.rb, line 344 def handle_no_method_error?(instance, error, caller) not_debugging?(instance) && error.message =~ \ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ end
Is `name` the name of a method defined in `instance` itself (not any super class)?
@param [Thor::Base] instance
The Thor instance this command is being run for.
@param [Symbol | String] name
The method name.
@return [Boolean]
`true` if `name` is the name of a method defined in `instance` itself.
# File lib/thor/command.rb, line 316 def local_method?(instance, name) methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) !(methods & [name.to_s, name.to_sym]).empty? end
# File lib/thor/command.rb, line 242 def not_debugging?(instance) !(instance.class.respond_to?(:debugging) && instance.class.debugging) end
Is this command's {#name} a private method of `instance`?
@param [Thor::Base] instance
The Thor instance this command is being run for.
@return [Boolean]
`true` if {#name} is a private method of `instance`.
# File lib/thor/command.rb, line 299 def private_method?(instance) !(instance.private_methods & [name.to_s, name.to_sym]).empty? end
# File lib/thor/command.rb, line 246 def required_options @required_options ||= options. map { |_, o| o.usage if o.required? }. compact. sort. join(" ") end
Is `name` a subcommand of `instance`?
@param [Thor::Base] instance
The Thor instance this command is being run for.
@param [Symbol | String] name
The subcommand / method name.
@return [return_type]
@todo Document return value.
# File lib/thor/command.rb, line 267 def subcommand? instance, name # It doesn't look like {Thor::Group} has `.subcommands`, so test for # that first. return false unless instance.class.respond_to?( :subcommands ) # See if the names is in the subcommands instance.class.subcommands.include? name.to_s end