Method: Thor::Command#run

Defined in:
lib/thor/command.rb

#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:



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
156
157
158
# 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