thor 0.16.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +15 -0
- data/README.md +23 -6
- data/bin/thor +1 -1
- data/lib/thor/actions/create_file.rb +34 -35
- data/lib/thor/actions/create_link.rb +9 -5
- data/lib/thor/actions/directory.rb +33 -23
- data/lib/thor/actions/empty_directory.rb +75 -85
- data/lib/thor/actions/file_manipulation.rb +103 -36
- data/lib/thor/actions/inject_into_file.rb +46 -36
- data/lib/thor/actions.rb +90 -68
- data/lib/thor/base.rb +302 -244
- data/lib/thor/command.rb +142 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
- data/lib/thor/error.rb +90 -10
- data/lib/thor/group.rb +70 -74
- data/lib/thor/invocation.rb +63 -55
- data/lib/thor/line_editor/basic.rb +37 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/nested_context.rb +29 -0
- data/lib/thor/parser/argument.rb +24 -28
- data/lib/thor/parser/arguments.rb +110 -102
- data/lib/thor/parser/option.rb +53 -15
- data/lib/thor/parser/options.rb +174 -97
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +12 -11
- data/lib/thor/runner.rb +159 -155
- data/lib/thor/shell/basic.rb +216 -93
- data/lib/thor/shell/color.rb +53 -40
- data/lib/thor/shell/html.rb +61 -58
- data/lib/thor/shell.rb +29 -36
- data/lib/thor/util.rb +231 -213
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +303 -166
- data/thor.gemspec +27 -24
- metadata +36 -226
- data/.gitignore +0 -44
- data/.rspec +0 -2
- data/.travis.yml +0 -7
- data/CHANGELOG.rdoc +0 -134
- data/Gemfile +0 -15
- data/Thorfile +0 -30
- data/bin/rake2thor +0 -86
- data/lib/thor/core_ext/dir_escape.rb +0 -0
- data/lib/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/thor/core_ext/ordered_hash.rb +0 -100
- data/lib/thor/task.rb +0 -132
- data/spec/actions/create_file_spec.rb +0 -170
- data/spec/actions/create_link_spec.rb +0 -81
- data/spec/actions/directory_spec.rb +0 -149
- data/spec/actions/empty_directory_spec.rb +0 -130
- data/spec/actions/file_manipulation_spec.rb +0 -370
- data/spec/actions/inject_into_file_spec.rb +0 -135
- data/spec/actions_spec.rb +0 -331
- data/spec/base_spec.rb +0 -279
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
- data/spec/core_ext/ordered_hash_spec.rb +0 -115
- data/spec/exit_condition_spec.rb +0 -19
- data/spec/fixtures/application.rb +0 -2
- data/spec/fixtures/app{1}/README +0 -3
- data/spec/fixtures/bundle/execute.rb +0 -6
- data/spec/fixtures/bundle/main.thor +0 -1
- data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
- data/spec/fixtures/doc/COMMENTER +0 -10
- data/spec/fixtures/doc/README +0 -3
- data/spec/fixtures/doc/block_helper.rb +0 -3
- data/spec/fixtures/doc/components/.empty_directory +0 -0
- data/spec/fixtures/doc/config.rb +0 -1
- data/spec/fixtures/doc/config.yaml.tt +0 -1
- data/spec/fixtures/enum.thor +0 -10
- data/spec/fixtures/group.thor +0 -114
- data/spec/fixtures/invoke.thor +0 -112
- data/spec/fixtures/path with spaces +0 -0
- data/spec/fixtures/script.thor +0 -190
- data/spec/fixtures/task.thor +0 -10
- data/spec/group_spec.rb +0 -216
- data/spec/invocation_spec.rb +0 -100
- data/spec/parser/argument_spec.rb +0 -53
- data/spec/parser/arguments_spec.rb +0 -66
- data/spec/parser/option_spec.rb +0 -202
- data/spec/parser/options_spec.rb +0 -330
- data/spec/rake_compat_spec.rb +0 -72
- data/spec/register_spec.rb +0 -135
- data/spec/runner_spec.rb +0 -241
- data/spec/shell/basic_spec.rb +0 -300
- data/spec/shell/color_spec.rb +0 -81
- data/spec/shell/html_spec.rb +0 -32
- data/spec/shell_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -59
- data/spec/task_spec.rb +0 -80
- data/spec/thor_spec.rb +0 -418
- data/spec/util_spec.rb +0 -196
data/lib/thor/base.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
require_relative "command"
|
2
|
+
require_relative "core_ext/hash_with_indifferent_access"
|
3
|
+
require_relative "error"
|
4
|
+
require_relative "invocation"
|
5
|
+
require_relative "nested_context"
|
6
|
+
require_relative "parser"
|
7
|
+
require_relative "shell"
|
8
|
+
require_relative "line_editor"
|
9
|
+
require_relative "util"
|
9
10
|
|
10
11
|
class Thor
|
11
|
-
autoload :Actions,
|
12
|
-
autoload :RakeCompat,
|
12
|
+
autoload :Actions, File.expand_path("actions", __dir__)
|
13
|
+
autoload :RakeCompat, File.expand_path("rake_compat", __dir__)
|
14
|
+
autoload :Group, File.expand_path("group", __dir__)
|
13
15
|
|
14
16
|
# Shortcuts for help.
|
15
17
|
HELP_MAPPINGS = %w(-h -? --help -D)
|
@@ -18,6 +20,17 @@ class Thor
|
|
18
20
|
THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
|
19
21
|
action add_file create_file in_root inside run run_ruby_script)
|
20
22
|
|
23
|
+
TEMPLATE_EXTNAME = ".tt"
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def deprecation_warning(message) #:nodoc:
|
27
|
+
unless ENV['THOR_SILENCE_DEPRECATION']
|
28
|
+
warn "Deprecation warning: #{message}\n" +
|
29
|
+
'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
21
34
|
module Base
|
22
35
|
attr_accessor :options, :parent_options, :args
|
23
36
|
|
@@ -37,7 +50,7 @@ class Thor
|
|
37
50
|
#
|
38
51
|
# config<Hash>:: Configuration for this Thor class.
|
39
52
|
#
|
40
|
-
def initialize(args=[],
|
53
|
+
def initialize(args = [], local_options = {}, config = {})
|
41
54
|
parse_options = self.class.class_options
|
42
55
|
|
43
56
|
# The start method splits inbound arguments at the first argument
|
@@ -45,21 +58,26 @@ class Thor
|
|
45
58
|
# new, passing in the two halves of the arguments Array as the
|
46
59
|
# first two parameters.
|
47
60
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
array_options
|
61
|
+
command_options = config.delete(:command_options) # hook for start
|
62
|
+
parse_options = parse_options.merge(command_options) if command_options
|
63
|
+
if local_options.is_a?(Array)
|
64
|
+
array_options = local_options
|
65
|
+
hash_options = {}
|
52
66
|
else
|
53
67
|
# Handle the case where the class was explicitly instantiated
|
54
68
|
# with pre-parsed options.
|
55
|
-
array_options
|
69
|
+
array_options = []
|
70
|
+
hash_options = local_options
|
56
71
|
end
|
57
72
|
|
58
73
|
# Let Thor::Options parse the options first, so it can remove
|
59
74
|
# declared options from the array. This will leave us with
|
60
75
|
# a list of arguments that weren't declared.
|
61
|
-
|
76
|
+
stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
|
77
|
+
disable_required_check = self.class.disable_required_check? config[:current_command]
|
78
|
+
opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check)
|
62
79
|
self.options = opts.parse(array_options)
|
80
|
+
self.options = config[:class_options].merge(options) if config[:class_options]
|
63
81
|
|
64
82
|
# If unknown options are disallowed, make sure that none of the
|
65
83
|
# remaining arguments looks like an option.
|
@@ -74,13 +92,14 @@ class Thor
|
|
74
92
|
to_parse += opts.remaining unless self.class.strict_args_position?(config)
|
75
93
|
|
76
94
|
thor_args = Thor::Arguments.new(self.class.arguments)
|
77
|
-
thor_args.parse(to_parse).each { |k,v|
|
95
|
+
thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) }
|
78
96
|
@args = thor_args.remaining
|
79
97
|
end
|
80
98
|
|
81
99
|
class << self
|
82
100
|
def included(base) #:nodoc:
|
83
|
-
base
|
101
|
+
super(base)
|
102
|
+
base.extend ClassMethods
|
84
103
|
base.send :include, Invocation
|
85
104
|
base.send :include, Shell
|
86
105
|
end
|
@@ -100,11 +119,11 @@ class Thor
|
|
100
119
|
# Hash[path<String> => Class]
|
101
120
|
#
|
102
121
|
def subclass_files
|
103
|
-
@subclass_files ||= Hash.new{ |h,k| h[k] = [] }
|
122
|
+
@subclass_files ||= Hash.new { |h, k| h[k] = [] }
|
104
123
|
end
|
105
124
|
|
106
125
|
# Whenever a class inherits from Thor or Thor::Group, we should track the
|
107
|
-
# class and the file on Thor::Base. This is the method
|
126
|
+
# class and the file on Thor::Base. This is the method responsible for it.
|
108
127
|
#
|
109
128
|
def register_klass_file(klass) #:nodoc:
|
110
129
|
file = caller[1].match(/(.*):\d+/)[1]
|
@@ -117,15 +136,15 @@ class Thor
|
|
117
136
|
|
118
137
|
module ClassMethods
|
119
138
|
def attr_reader(*) #:nodoc:
|
120
|
-
|
139
|
+
no_commands { super }
|
121
140
|
end
|
122
141
|
|
123
142
|
def attr_writer(*) #:nodoc:
|
124
|
-
|
143
|
+
no_commands { super }
|
125
144
|
end
|
126
145
|
|
127
146
|
def attr_accessor(*) #:nodoc:
|
128
|
-
|
147
|
+
no_commands { super }
|
129
148
|
end
|
130
149
|
|
131
150
|
# If you want to raise an error for unknown options, call check_unknown_options!
|
@@ -142,6 +161,37 @@ class Thor
|
|
142
161
|
!!check_unknown_options
|
143
162
|
end
|
144
163
|
|
164
|
+
# If you want to raise an error when the default value of an option does not match
|
165
|
+
# the type call check_default_type!
|
166
|
+
# This will be the default; for compatibility a deprecation warning is issued if necessary.
|
167
|
+
def check_default_type!
|
168
|
+
@check_default_type = true
|
169
|
+
end
|
170
|
+
|
171
|
+
# If you want to use defaults that don't match the type of an option,
|
172
|
+
# either specify `check_default_type: false` or call `allow_incompatible_default_type!`
|
173
|
+
def allow_incompatible_default_type!
|
174
|
+
@check_default_type = false
|
175
|
+
end
|
176
|
+
|
177
|
+
def check_default_type #:nodoc:
|
178
|
+
@check_default_type = from_superclass(:check_default_type, nil) unless defined?(@check_default_type)
|
179
|
+
@check_default_type
|
180
|
+
end
|
181
|
+
|
182
|
+
# If true, option parsing is suspended as soon as an unknown option or a
|
183
|
+
# regular argument is encountered. All remaining arguments are passed to
|
184
|
+
# the command as regular arguments.
|
185
|
+
def stop_on_unknown_option?(command_name) #:nodoc:
|
186
|
+
false
|
187
|
+
end
|
188
|
+
|
189
|
+
# If true, option set will not suspend the execution of the command when
|
190
|
+
# a required option is not provided.
|
191
|
+
def disable_required_check?(command_name) #:nodoc:
|
192
|
+
false
|
193
|
+
end
|
194
|
+
|
145
195
|
# If you want only strict string args (useful when cascading thor classes),
|
146
196
|
# call strict_args_position! This is disabled by default to allow dynamic
|
147
197
|
# invocations.
|
@@ -163,11 +213,11 @@ class Thor
|
|
163
213
|
# is how they are parsed from the command line, arguments are retrieved
|
164
214
|
# from position:
|
165
215
|
#
|
166
|
-
# thor
|
216
|
+
# thor command NAME
|
167
217
|
#
|
168
218
|
# Instead of:
|
169
219
|
#
|
170
|
-
# thor
|
220
|
+
# thor command --name=NAME
|
171
221
|
#
|
172
222
|
# Besides, arguments are used inside your code as an accessor (self.argument),
|
173
223
|
# while options are all kept in a hash (self.options).
|
@@ -192,9 +242,9 @@ class Thor
|
|
192
242
|
# ==== Errors
|
193
243
|
# ArgumentError:: Raised if you supply a required argument after a non required one.
|
194
244
|
#
|
195
|
-
def argument(name, options={})
|
245
|
+
def argument(name, options = {})
|
196
246
|
is_thor_reserved_word?(name, :argument)
|
197
|
-
|
247
|
+
no_commands { attr_accessor name }
|
198
248
|
|
199
249
|
required = if options.key?(:optional)
|
200
250
|
!options[:optional]
|
@@ -206,11 +256,13 @@ class Thor
|
|
206
256
|
|
207
257
|
remove_argument name
|
208
258
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
259
|
+
if required
|
260
|
+
arguments.each do |argument|
|
261
|
+
next if argument.required?
|
262
|
+
raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \
|
263
|
+
"the non-required argument #{argument.human_name.inspect}."
|
264
|
+
end
|
265
|
+
end
|
214
266
|
|
215
267
|
options[:required] = required
|
216
268
|
|
@@ -235,7 +287,7 @@ class Thor
|
|
235
287
|
# ==== Parameters
|
236
288
|
# Hash[Symbol => Object]
|
237
289
|
#
|
238
|
-
def class_options(options=nil)
|
290
|
+
def class_options(options = nil)
|
239
291
|
@class_options ||= from_superclass(:class_options, {})
|
240
292
|
build_options(options, @class_options) if options
|
241
293
|
@class_options
|
@@ -257,7 +309,7 @@ class Thor
|
|
257
309
|
# :banner:: -- String to show on usage notes.
|
258
310
|
# :hide:: -- If you want to hide this option from the help.
|
259
311
|
#
|
260
|
-
def class_option(name, options={})
|
312
|
+
def class_option(name, options = {})
|
261
313
|
build_option(name, options, class_options)
|
262
314
|
end
|
263
315
|
|
@@ -298,87 +350,96 @@ class Thor
|
|
298
350
|
end
|
299
351
|
|
300
352
|
# Defines the group. This is used when thor list is invoked so you can specify
|
301
|
-
# that only
|
353
|
+
# that only commands from a pre-defined group will be shown. Defaults to standard.
|
302
354
|
#
|
303
355
|
# ==== Parameters
|
304
356
|
# name<String|Symbol>
|
305
357
|
#
|
306
|
-
def group(name=nil)
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
@group = name.to_s
|
358
|
+
def group(name = nil)
|
359
|
+
if name
|
360
|
+
@group = name.to_s
|
361
|
+
else
|
362
|
+
@group ||= from_superclass(:group, "standard")
|
312
363
|
end
|
313
364
|
end
|
314
365
|
|
315
|
-
# Returns the
|
366
|
+
# Returns the commands for this Thor class.
|
316
367
|
#
|
317
368
|
# ==== Returns
|
318
|
-
#
|
319
|
-
#
|
369
|
+
# Hash:: An ordered hash with commands names as keys and Thor::Command
|
370
|
+
# objects as values.
|
320
371
|
#
|
321
|
-
def
|
322
|
-
@
|
372
|
+
def commands
|
373
|
+
@commands ||= Hash.new
|
323
374
|
end
|
375
|
+
alias_method :tasks, :commands
|
324
376
|
|
325
|
-
# Returns the
|
377
|
+
# Returns the commands for this Thor class and all subclasses.
|
326
378
|
#
|
327
379
|
# ==== Returns
|
328
|
-
#
|
329
|
-
#
|
380
|
+
# Hash:: An ordered hash with commands names as keys and Thor::Command
|
381
|
+
# objects as values.
|
330
382
|
#
|
331
|
-
def
|
332
|
-
@
|
333
|
-
@
|
383
|
+
def all_commands
|
384
|
+
@all_commands ||= from_superclass(:all_commands, Hash.new)
|
385
|
+
@all_commands.merge!(commands)
|
334
386
|
end
|
387
|
+
alias_method :all_tasks, :all_commands
|
335
388
|
|
336
|
-
# Removes a given
|
389
|
+
# Removes a given command from this Thor class. This is usually done if you
|
337
390
|
# are inheriting from another class and don't want it to be available
|
338
391
|
# anymore.
|
339
392
|
#
|
340
|
-
# By default it only remove the mapping to the
|
393
|
+
# By default it only remove the mapping to the command. But you can supply
|
341
394
|
# :undefine => true to undefine the method from the class as well.
|
342
395
|
#
|
343
396
|
# ==== Parameters
|
344
|
-
# name<Symbol|String>:: The name of the
|
345
|
-
# options<Hash>:: You can give :undefine => true if you want
|
397
|
+
# name<Symbol|String>:: The name of the command to be removed
|
398
|
+
# options<Hash>:: You can give :undefine => true if you want commands the method
|
346
399
|
# to be undefined from the class as well.
|
347
400
|
#
|
348
|
-
def
|
401
|
+
def remove_command(*names)
|
349
402
|
options = names.last.is_a?(Hash) ? names.pop : {}
|
350
403
|
|
351
404
|
names.each do |name|
|
352
|
-
|
353
|
-
|
405
|
+
commands.delete(name.to_s)
|
406
|
+
all_commands.delete(name.to_s)
|
354
407
|
undef_method name if options[:undefine]
|
355
408
|
end
|
356
409
|
end
|
410
|
+
alias_method :remove_task, :remove_command
|
357
411
|
|
358
|
-
# All methods defined inside the given block are not added as
|
412
|
+
# All methods defined inside the given block are not added as commands.
|
359
413
|
#
|
360
414
|
# So you can do:
|
361
415
|
#
|
362
416
|
# class MyScript < Thor
|
363
|
-
#
|
364
|
-
# def
|
417
|
+
# no_commands do
|
418
|
+
# def this_is_not_a_command
|
365
419
|
# end
|
366
420
|
# end
|
367
421
|
# end
|
368
422
|
#
|
369
|
-
# You can also add the method and remove it from the
|
423
|
+
# You can also add the method and remove it from the command list:
|
370
424
|
#
|
371
425
|
# class MyScript < Thor
|
372
|
-
# def
|
426
|
+
# def this_is_not_a_command
|
373
427
|
# end
|
374
|
-
#
|
428
|
+
# remove_command :this_is_not_a_command
|
375
429
|
# end
|
376
430
|
#
|
377
|
-
def
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
431
|
+
def no_commands(&block)
|
432
|
+
no_commands_context.enter(&block)
|
433
|
+
end
|
434
|
+
|
435
|
+
alias_method :no_tasks, :no_commands
|
436
|
+
|
437
|
+
def no_commands_context
|
438
|
+
@no_commands_context ||= NestedContext.new
|
439
|
+
end
|
440
|
+
|
441
|
+
def no_commands?
|
442
|
+
no_commands_context.entered?
|
382
443
|
end
|
383
444
|
|
384
445
|
# Sets the namespace for the Thor or Thor::Group class. By default the
|
@@ -391,7 +452,7 @@ class Thor
|
|
391
452
|
#
|
392
453
|
# namespace :my_scripts
|
393
454
|
#
|
394
|
-
# You change how your
|
455
|
+
# You change how your commands are invoked:
|
395
456
|
#
|
396
457
|
# thor my_scripts -h
|
397
458
|
#
|
@@ -399,243 +460,240 @@ class Thor
|
|
399
460
|
#
|
400
461
|
# namespace :default
|
401
462
|
#
|
402
|
-
# Your
|
463
|
+
# Your commands can be invoked with a shortcut. Instead of:
|
403
464
|
#
|
404
|
-
# thor :
|
465
|
+
# thor :my_command
|
405
466
|
#
|
406
|
-
def namespace(name=nil)
|
407
|
-
|
408
|
-
when nil
|
409
|
-
@namespace ||= Thor::Util.namespace_from_thor_class(self)
|
410
|
-
else
|
467
|
+
def namespace(name = nil)
|
468
|
+
if name
|
411
469
|
@namespace = name.to_s
|
470
|
+
else
|
471
|
+
@namespace ||= Thor::Util.namespace_from_thor_class(self)
|
412
472
|
end
|
413
473
|
end
|
414
474
|
|
415
|
-
# Parses the
|
416
|
-
# and invoke the
|
475
|
+
# Parses the command and options from the given args, instantiate the class
|
476
|
+
# and invoke the command. This method is used when the arguments must be parsed
|
417
477
|
# from an array. If you are inside Ruby and want to use a Thor class, you
|
418
478
|
# can simply initialize it:
|
419
479
|
#
|
420
480
|
# script = MyScript.new(args, options, config)
|
421
|
-
# script.invoke(:
|
481
|
+
# script.invoke(:command, first_arg, second_arg, third_arg)
|
422
482
|
#
|
423
|
-
def start(given_args=ARGV, config={})
|
483
|
+
def start(given_args = ARGV, config = {})
|
424
484
|
config[:shell] ||= Thor::Base.shell.new
|
425
485
|
dispatch(nil, given_args.dup, nil, config)
|
426
486
|
rescue Thor::Error => e
|
427
|
-
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
|
428
|
-
exit(
|
487
|
+
config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
|
488
|
+
exit(false) if exit_on_failure?
|
429
489
|
rescue Errno::EPIPE
|
430
|
-
# This happens if a thor
|
490
|
+
# This happens if a thor command is piped to something like `head`,
|
431
491
|
# which closes the pipe when it's done reading. This will also
|
432
492
|
# mean that if the pipe is closed, further unnecessary
|
433
493
|
# computation will not occur.
|
434
|
-
exit(
|
494
|
+
exit(true)
|
435
495
|
end
|
436
496
|
|
437
|
-
# Allows to use private methods from parent in child classes as
|
497
|
+
# Allows to use private methods from parent in child classes as commands.
|
438
498
|
#
|
439
499
|
# ==== Parameters
|
440
|
-
# names<Array>:: Method names to be used as
|
500
|
+
# names<Array>:: Method names to be used as commands
|
441
501
|
#
|
442
502
|
# ==== Examples
|
443
503
|
#
|
444
|
-
#
|
445
|
-
#
|
504
|
+
# public_command :foo
|
505
|
+
# public_command :foo, :bar, :baz
|
446
506
|
#
|
447
|
-
def
|
507
|
+
def public_command(*names)
|
448
508
|
names.each do |name|
|
449
509
|
class_eval "def #{name}(*); super end"
|
450
510
|
end
|
451
511
|
end
|
512
|
+
alias_method :public_task, :public_command
|
452
513
|
|
453
|
-
def
|
454
|
-
if has_namespace
|
455
|
-
raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
|
456
|
-
else
|
457
|
-
raise UndefinedTaskError, "Could not find task #{task.inspect}."
|
458
|
-
end
|
514
|
+
def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
|
515
|
+
raise UndefinedCommandError.new(command, all_commands.keys, (namespace if has_namespace))
|
459
516
|
end
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
msg = "call #{msg} as"
|
469
|
-
end
|
470
|
-
|
471
|
-
msg << ": #{self.banner(task).inspect}."
|
517
|
+
alias_method :handle_no_task_error, :handle_no_command_error
|
518
|
+
|
519
|
+
def handle_argument_error(command, error, args, arity) #:nodoc:
|
520
|
+
name = [command.ancestor_name, command.name].compact.join(" ")
|
521
|
+
msg = "ERROR: \"#{basename} #{name}\" was called with ".dup
|
522
|
+
msg << "no arguments" if args.empty?
|
523
|
+
msg << "arguments " << args.inspect unless args.empty?
|
524
|
+
msg << "\nUsage: \"#{banner(command).split("\n").join("\"\n \"")}\""
|
472
525
|
raise InvocationError, msg
|
473
526
|
end
|
474
527
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
def class_options_help(shell, groups={}) #:nodoc:
|
481
|
-
# Group options by group
|
482
|
-
class_options.each do |_, value|
|
483
|
-
groups[value.group] ||= []
|
484
|
-
groups[value.group] << value
|
485
|
-
end
|
528
|
+
# A flag that makes the process exit with status 1 if any error happens.
|
529
|
+
def exit_on_failure?
|
530
|
+
Thor.deprecation_warning "Thor exit with status 0 on errors. To keep this behavior, you must define `exit_on_failure?` in `#{self.name}`"
|
531
|
+
false
|
532
|
+
end
|
486
533
|
|
487
|
-
|
488
|
-
global_options = groups.delete(nil) || []
|
489
|
-
print_options(shell, global_options)
|
534
|
+
protected
|
490
535
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
536
|
+
# Prints the class options per group. If an option does not belong to
|
537
|
+
# any group, it's printed as Class option.
|
538
|
+
#
|
539
|
+
def class_options_help(shell, groups = {}) #:nodoc:
|
540
|
+
# Group options by group
|
541
|
+
class_options.each do |_, value|
|
542
|
+
groups[value.group] ||= []
|
543
|
+
groups[value.group] << value
|
495
544
|
end
|
496
545
|
|
497
|
-
#
|
498
|
-
|
499
|
-
|
546
|
+
# Deal with default group
|
547
|
+
global_options = groups.delete(nil) || []
|
548
|
+
print_options(shell, global_options)
|
500
549
|
|
501
|
-
|
502
|
-
|
550
|
+
# Print all others
|
551
|
+
groups.each do |group_name, options|
|
552
|
+
print_options(shell, options, group_name)
|
553
|
+
end
|
554
|
+
end
|
503
555
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
item.push(option.description ? "# #{option.description}" : "")
|
556
|
+
# Receives a set of options and print them.
|
557
|
+
def print_options(shell, options, group_name = nil)
|
558
|
+
return if options.empty?
|
508
559
|
|
509
|
-
|
510
|
-
|
511
|
-
list << [ "", "# Possible values: #{option.enum.join(', ')}" ] if option.enum
|
512
|
-
end
|
513
|
-
end
|
560
|
+
list = []
|
561
|
+
padding = options.map { |o| o.aliases.size }.max.to_i * 4
|
514
562
|
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
563
|
+
options.each do |option|
|
564
|
+
next if option.hide
|
565
|
+
item = [option.usage(padding)]
|
566
|
+
item.push(option.description ? "# #{option.description}" : "")
|
519
567
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
|
568
|
+
list << item
|
569
|
+
list << ["", "# Default: #{option.default}"] if option.show_default?
|
570
|
+
list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum
|
524
571
|
end
|
525
572
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
# options<Hash>:: Described in both class_option and method_option.
|
531
|
-
# scope<Hash>:: Options hash that is being built up
|
532
|
-
def build_option(name, options, scope) #:nodoc:
|
533
|
-
scope[name] = Thor::Option.new(name, options)
|
534
|
-
end
|
573
|
+
shell.say(group_name ? "#{group_name} options:" : "Options:")
|
574
|
+
shell.print_table(list, :indent => 2)
|
575
|
+
shell.say ""
|
576
|
+
end
|
535
577
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
#
|
540
|
-
|
541
|
-
# ==== Parameters
|
542
|
-
# Hash[Symbol => Object]
|
543
|
-
def build_options(options, scope) #:nodoc:
|
544
|
-
options.each do |key, value|
|
545
|
-
scope[key] = Thor::Option.parse(key, value)
|
546
|
-
end
|
547
|
-
end
|
578
|
+
# Raises an error if the word given is a Thor reserved word.
|
579
|
+
def is_thor_reserved_word?(word, type) #:nodoc:
|
580
|
+
return false unless THOR_RESERVED_WORDS.include?(word.to_s)
|
581
|
+
raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
|
582
|
+
end
|
548
583
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
584
|
+
# Build an option and adds it to the given scope.
|
585
|
+
#
|
586
|
+
# ==== Parameters
|
587
|
+
# name<Symbol>:: The name of the argument.
|
588
|
+
# options<Hash>:: Described in both class_option and method_option.
|
589
|
+
# scope<Hash>:: Options hash that is being built up
|
590
|
+
def build_option(name, options, scope) #:nodoc:
|
591
|
+
scope[name] = Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options))
|
592
|
+
end
|
593
|
+
|
594
|
+
# Receives a hash of options, parse them and add to the scope. This is a
|
595
|
+
# fast way to set a bunch of options:
|
596
|
+
#
|
597
|
+
# build_options :foo => true, :bar => :required, :baz => :string
|
598
|
+
#
|
599
|
+
# ==== Parameters
|
600
|
+
# Hash[Symbol => Object]
|
601
|
+
def build_options(options, scope) #:nodoc:
|
602
|
+
options.each do |key, value|
|
603
|
+
scope[key] = Thor::Option.parse(key, value)
|
560
604
|
end
|
605
|
+
end
|
561
606
|
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
607
|
+
# Finds a command with the given name. If the command belongs to the current
|
608
|
+
# class, just return it, otherwise dup it and add the fresh copy to the
|
609
|
+
# current command hash.
|
610
|
+
def find_and_refresh_command(name) #:nodoc:
|
611
|
+
if commands[name.to_s]
|
612
|
+
commands[name.to_s]
|
613
|
+
elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
|
614
|
+
commands[name.to_s] = command.clone
|
615
|
+
else
|
616
|
+
raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
|
567
617
|
end
|
618
|
+
end
|
619
|
+
alias_method :find_and_refresh_task, :find_and_refresh_command
|
620
|
+
|
621
|
+
# Everytime someone inherits from a Thor class, register the klass
|
622
|
+
# and file into baseclass.
|
623
|
+
def inherited(klass)
|
624
|
+
super(klass)
|
625
|
+
Thor::Base.register_klass_file(klass)
|
626
|
+
klass.instance_variable_set(:@no_commands, 0)
|
627
|
+
end
|
568
628
|
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
629
|
+
# Fire this callback whenever a method is added. Added methods are
|
630
|
+
# tracked as commands by invoking the create_command method.
|
631
|
+
def method_added(meth)
|
632
|
+
super(meth)
|
633
|
+
meth = meth.to_s
|
573
634
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
635
|
+
if meth == "initialize"
|
636
|
+
initialize_added
|
637
|
+
return
|
638
|
+
end
|
578
639
|
|
579
|
-
|
580
|
-
|
581
|
-
public_instance_methods.include?(meth.to_sym)
|
640
|
+
# Return if it's not a public instance method
|
641
|
+
return unless public_method_defined?(meth.to_sym)
|
582
642
|
|
583
|
-
|
643
|
+
return if no_commands? || !create_command(meth)
|
584
644
|
|
585
|
-
|
586
|
-
|
587
|
-
|
645
|
+
is_thor_reserved_word?(meth, :command)
|
646
|
+
Thor::Base.register_klass_file(self)
|
647
|
+
end
|
588
648
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
649
|
+
# Retrieves a value from superclass. If it reaches the baseclass,
|
650
|
+
# returns default.
|
651
|
+
def from_superclass(method, default = nil)
|
652
|
+
if self == baseclass || !superclass.respond_to?(method, true)
|
653
|
+
default
|
654
|
+
else
|
655
|
+
value = superclass.send(method)
|
656
|
+
|
657
|
+
# Ruby implements `dup` on Object, but raises a `TypeError`
|
658
|
+
# if the method is called on immediates. As a result, we
|
659
|
+
# don't have a good way to check whether dup will succeed
|
660
|
+
# without calling it and rescuing the TypeError.
|
661
|
+
begin
|
662
|
+
value.dup
|
663
|
+
rescue TypeError
|
664
|
+
value
|
604
665
|
end
|
605
|
-
end
|
606
|
-
|
607
|
-
# A flag that makes the process exit with status 1 if any error happens.
|
608
|
-
def exit_on_failure?
|
609
|
-
false
|
610
|
-
end
|
611
666
|
|
612
|
-
#
|
613
|
-
# The basename of the program invoking the thor class.
|
614
|
-
#
|
615
|
-
def basename
|
616
|
-
File.basename($0).split(' ').first
|
617
667
|
end
|
668
|
+
end
|
618
669
|
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
670
|
+
#
|
671
|
+
# The basename of the program invoking the thor class.
|
672
|
+
#
|
673
|
+
def basename
|
674
|
+
File.basename($PROGRAM_NAME).split(" ").first
|
675
|
+
end
|
623
676
|
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
677
|
+
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
678
|
+
# finishes.
|
679
|
+
def baseclass #:nodoc:
|
680
|
+
end
|
628
681
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
682
|
+
# SIGNATURE: Creates a new command if valid_command? is true. This method is
|
683
|
+
# called when a new method is added to the class.
|
684
|
+
def create_command(meth) #:nodoc:
|
685
|
+
end
|
686
|
+
alias_method :create_task, :create_command
|
633
687
|
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
688
|
+
# SIGNATURE: Defines behavior when the initialize method is added to the
|
689
|
+
# class.
|
690
|
+
def initialize_added #:nodoc:
|
691
|
+
end
|
638
692
|
|
693
|
+
# SIGNATURE: The hook invoked by start.
|
694
|
+
def dispatch(command, given_args, given_opts, config) #:nodoc:
|
695
|
+
raise NotImplementedError
|
696
|
+
end
|
639
697
|
end
|
640
698
|
end
|
641
699
|
end
|