Class: Thor::Command

Inherits:
Struct
  • Object
show all
Includes:
SemanticLogger::Loggable, Thor::Completion::Bash::Command
Defined in:
lib/thor/command.rb

Direct Known Subclasses

DynamicCommand, HiddenCommand

Constant Summary collapse

FILE_REGEXP =
/^#{Regexp.escape(File.dirname(__FILE__))}/

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Thor::Completion::Bash::Command

#bash_complete

Constructor Details

#initialize(name:, description: nil, long_description: nil, usage: nil, examples: [], options: nil) ⇒ Command

Returns a new instance of Command.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/thor/command.rb', line 17

def initialize  name:,
                description: nil,
                long_description: nil,
                usage: nil,
                examples: [],
                options: nil
  super \
    name.to_s,
    description,
    long_description,
    usage,
    examples,
    options || {}
end

Instance Attribute Details

#ancestor_nameObject

Returns the value of attribute ancestor_name

Returns:

  • (Object)

    the current value of ancestor_name



5
6
7
# File 'lib/thor/command.rb', line 5

def ancestor_name
  @ancestor_name
end

#descriptionObject

Returns the value of attribute description

Returns:

  • (Object)

    the current value of description



5
6
7
# File 'lib/thor/command.rb', line 5

def description
  @description
end

#examplesObject

Returns the value of attribute examples

Returns:

  • (Object)

    the current value of examples



5
6
7
# File 'lib/thor/command.rb', line 5

def examples
  @examples
end

#long_descriptionObject

Returns the value of attribute long_description

Returns:

  • (Object)

    the current value of long_description



5
6
7
# File 'lib/thor/command.rb', line 5

def long_description
  @long_description
end

#nameObject

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



5
6
7
# File 'lib/thor/command.rb', line 5

def name
  @name
end

#optionsObject

Returns the value of attribute options

Returns:

  • (Object)

    the current value of options



5
6
7
# File 'lib/thor/command.rb', line 5

def options
  @options
end

#usageObject

Returns the value of attribute usage

Returns:

  • (Object)

    the current value of usage



5
6
7
# File 'lib/thor/command.rb', line 5

def usage
  @usage
end

Instance Method Details

#formatted_usage(klass, namespace = true, subcommand = false) ⇒ Object

Returns the formatted usage by injecting given required arguments and required options into the given usage.



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
# File 'lib/thor/command.rb', line 160

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
  formatted << if klass && !klass.arguments.empty?
                 usage.to_s.gsub(/^#{name}/) do |match|
                   match  << " " \
                          << klass.arguments.map(&:usage).compact.join(" ")
                 end
               else
                 usage.to_s
               end

  # Add required options
  formatted << " #{required_options}"

  # Strip and go!
  formatted.strip
end

#handle_argument_error?(instance, error, caller) ⇒ Boolean (protected)

Returns:

  • (Boolean)


288
289
290
291
292
293
294
295
296
297
# File 'lib/thor/command.rb', line 288

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

#handle_no_method_error?(instance, error, caller) ⇒ Boolean (protected)

Returns:

  • (Boolean)


299
300
301
302
303
# File 'lib/thor/command.rb', line 299

def handle_no_method_error?(instance, error, caller)
  not_debugging?(instance) &&
    error.message =~ \
      /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
end

#hidden?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/thor/command.rb', line 37

def hidden?
  false
end

#initialize_copy(other) ⇒ Object

:nodoc:



32
33
34
35
# File 'lib/thor/command.rb', line 32

def initialize_copy(other) #:nodoc:
  super(other)
  self.options = other.options.dup if other.options
end

#local_method?(instance, name) ⇒ Boolean (protected)

Is ‘name` the name of a method defined in `instance` itself (not any super class)?

Parameters:

  • instance (Thor::Base)

    The Thor instance this command is being run for.

  • name (Symbol | String)

    The method name.

Returns:

  • (Boolean)

    ‘true` if `name` is the name of a method defined in `instance` itself.



271
272
273
274
275
276
# File 'lib/thor/command.rb', line 271

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

#not_debugging?(instance) ⇒ Boolean (protected)

Returns:

  • (Boolean)


197
198
199
# File 'lib/thor/command.rb', line 197

def not_debugging?(instance)
  !(instance.class.respond_to?(:debugging) && instance.class.debugging)
end

#private_method?(instance) ⇒ Boolean (protected)

Is this command’s #name a private method of ‘instance`?

Parameters:

  • instance (Thor::Base)

    The Thor instance this command is being run for.

Returns:

  • (Boolean)

    ‘true` if #name is a private method of `instance`.



254
255
256
# File 'lib/thor/command.rb', line 254

def private_method?(instance)
  !(instance.private_methods & [name.to_s, name.to_sym]).empty?
end

#public_method?(instance) ⇒ Boolean (protected)

Is this command’s #name a public method of ‘instance`?

Parameters:

  • instance (Thor::Base)

    The Thor instance this command is being run for.

Returns:

  • (Boolean)

    ‘true` if #name is a public method of `instance`.



241
242
243
# File 'lib/thor/command.rb', line 241

def public_method?(instance) #:nodoc:
  !(instance.public_methods & [name.to_s, name.to_sym]).empty?
end

#required_optionsObject (protected)



201
202
203
204
205
206
207
# File 'lib/thor/command.rb', line 201

def required_options
  @required_options ||= options.
    map { |_, o| o.usage if o.required? }.
    compact.
    sort.
    join(" ")
end

#run(instance, args = []) ⇒ Object

Run a command by calling the actual method on the Base instance.

By default, a command invokes a method in the thor class. You can change this implementation to create custom commands.

Parameters:

  • instance (Thor::Base)

    Thor class instance the command is being run for.

  • args (Array<?>) (defaults to: [])

    Arguments for the command.

Returns:

  • The return value of the command method on ‘instance`.

Raises:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/thor/command.rb', line 61

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

#sans_backtrace(backtrace, caller) ⇒ Object (protected)

:nodoc:



279
280
281
282
283
284
285
286
# File 'lib/thor/command.rb', line 279

def sans_backtrace(backtrace, caller) #:nodoc:
  saned = backtrace.reject { |frame|
    (frame =~ FILE_REGEXP) ||
    (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) ||
    (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/)
  }
  saned - caller
end

#subcommand?(instance, name) ⇒ return_type (protected)

Is ‘name` a subcommand of `instance`?

Parameters:

  • instance (Thor::Base)

    The Thor instance this command is being run for.

  • name (Symbol | String)

    The subcommand / method name.

Returns:

  • (return_type)

    @todo Document return value.



222
223
224
225
226
227
228
229
# File 'lib/thor/command.rb', line 222

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