thor 0.18.1 → 0.19.0

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +13 -7
  3. data/Thorfile +4 -5
  4. data/bin/thor +1 -1
  5. data/lib/thor.rb +78 -67
  6. data/lib/thor/actions.rb +57 -56
  7. data/lib/thor/actions/create_file.rb +33 -35
  8. data/lib/thor/actions/create_link.rb +2 -3
  9. data/lib/thor/actions/directory.rb +37 -38
  10. data/lib/thor/actions/empty_directory.rb +67 -69
  11. data/lib/thor/actions/file_manipulation.rb +17 -15
  12. data/lib/thor/actions/inject_into_file.rb +27 -29
  13. data/lib/thor/base.rb +193 -189
  14. data/lib/thor/command.rb +20 -23
  15. data/lib/thor/core_ext/hash_with_indifferent_access.rb +21 -24
  16. data/lib/thor/core_ext/io_binary_read.rb +2 -4
  17. data/lib/thor/core_ext/ordered_hash.rb +9 -11
  18. data/lib/thor/error.rb +5 -1
  19. data/lib/thor/group.rb +53 -54
  20. data/lib/thor/invocation.rb +44 -38
  21. data/lib/thor/line_editor.rb +17 -0
  22. data/lib/thor/line_editor/basic.rb +35 -0
  23. data/lib/thor/line_editor/readline.rb +88 -0
  24. data/lib/thor/parser.rb +4 -4
  25. data/lib/thor/parser/argument.rb +28 -29
  26. data/lib/thor/parser/arguments.rb +102 -98
  27. data/lib/thor/parser/option.rb +26 -22
  28. data/lib/thor/parser/options.rb +86 -86
  29. data/lib/thor/rake_compat.rb +9 -10
  30. data/lib/thor/runner.rb +141 -141
  31. data/lib/thor/shell.rb +27 -34
  32. data/lib/thor/shell/basic.rb +91 -63
  33. data/lib/thor/shell/color.rb +44 -43
  34. data/lib/thor/shell/html.rb +59 -60
  35. data/lib/thor/util.rb +24 -27
  36. data/lib/thor/version.rb +1 -1
  37. data/spec/actions/create_file_spec.rb +25 -27
  38. data/spec/actions/create_link_spec.rb +19 -18
  39. data/spec/actions/directory_spec.rb +31 -31
  40. data/spec/actions/empty_directory_spec.rb +18 -18
  41. data/spec/actions/file_manipulation_spec.rb +38 -28
  42. data/spec/actions/inject_into_file_spec.rb +13 -13
  43. data/spec/actions_spec.rb +43 -43
  44. data/spec/base_spec.rb +45 -38
  45. data/spec/command_spec.rb +13 -14
  46. data/spec/core_ext/hash_with_indifferent_access_spec.rb +19 -19
  47. data/spec/core_ext/ordered_hash_spec.rb +6 -6
  48. data/spec/exit_condition_spec.rb +4 -4
  49. data/spec/fixtures/invoke.thor +19 -0
  50. data/spec/fixtures/script.thor +1 -1
  51. data/spec/group_spec.rb +30 -24
  52. data/spec/helper.rb +28 -15
  53. data/spec/invocation_spec.rb +39 -19
  54. data/spec/line_editor/basic_spec.rb +28 -0
  55. data/spec/line_editor/readline_spec.rb +69 -0
  56. data/spec/line_editor_spec.rb +43 -0
  57. data/spec/parser/argument_spec.rb +12 -12
  58. data/spec/parser/arguments_spec.rb +11 -11
  59. data/spec/parser/option_spec.rb +33 -25
  60. data/spec/parser/options_spec.rb +66 -52
  61. data/spec/quality_spec.rb +75 -0
  62. data/spec/rake_compat_spec.rb +10 -10
  63. data/spec/register_spec.rb +60 -30
  64. data/spec/runner_spec.rb +67 -62
  65. data/spec/sandbox/application.rb +2 -0
  66. data/spec/sandbox/app{1}/README +3 -0
  67. data/spec/sandbox/bundle/execute.rb +6 -0
  68. data/spec/sandbox/bundle/main.thor +1 -0
  69. data/spec/sandbox/command.thor +10 -0
  70. data/spec/sandbox/doc/%file_name%.rb.tt +1 -0
  71. data/spec/sandbox/doc/COMMENTER +11 -0
  72. data/spec/sandbox/doc/README +3 -0
  73. data/spec/sandbox/doc/block_helper.rb +3 -0
  74. data/spec/sandbox/doc/config.rb +1 -0
  75. data/spec/sandbox/doc/config.yaml.tt +1 -0
  76. data/spec/sandbox/doc/excluding/%file_name%.rb.tt +1 -0
  77. data/spec/sandbox/enum.thor +10 -0
  78. data/spec/sandbox/group.thor +128 -0
  79. data/spec/sandbox/invoke.thor +131 -0
  80. data/spec/sandbox/path with spaces b/data/spec/sandbox/path with → spaces +0 -0
  81. data/spec/sandbox/preserve/script.sh +3 -0
  82. data/spec/sandbox/script.thor +220 -0
  83. data/spec/sandbox/subcommand.thor +17 -0
  84. data/spec/shell/basic_spec.rb +107 -86
  85. data/spec/shell/color_spec.rb +32 -8
  86. data/spec/shell/html_spec.rb +3 -4
  87. data/spec/shell_spec.rb +7 -7
  88. data/spec/subcommand_spec.rb +20 -2
  89. data/spec/thor_spec.rb +111 -97
  90. data/spec/util_spec.rb +30 -30
  91. data/thor.gemspec +14 -14
  92. metadata +69 -25
@@ -1,8 +1,7 @@
1
- require 'thor/actions/empty_directory'
1
+ require "thor/actions/empty_directory"
2
2
 
3
3
  class Thor
4
4
  module Actions
5
-
6
5
  # Injects the given content into a file. Different from gsub_file, this
7
6
  # method is reversible.
8
7
  #
@@ -36,13 +35,13 @@ class Thor
36
35
  attr_reader :replacement, :flag, :behavior
37
36
 
38
37
  def initialize(base, destination, data, config)
39
- super(base, destination, { :verbose => true }.merge(config))
38
+ super(base, destination, {:verbose => true}.merge(config))
40
39
 
41
40
  @behavior, @flag = if @config.key?(:after)
42
41
  [:after, @config.delete(:after)]
43
- else
44
- [:before, @config.delete(:before)]
45
- end
42
+ else
43
+ [:before, @config.delete(:before)]
44
+ end
46
45
 
47
46
  @replacement = data.is_a?(Proc) ? data.call : data
48
47
  @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
@@ -74,36 +73,35 @@ class Thor
74
73
  replace!(regexp, content, true)
75
74
  end
76
75
 
77
- protected
76
+ protected
78
77
 
79
- def say_status(behavior)
80
- status = if behavior == :invoke
81
- if flag == /\A/
82
- :prepend
83
- elsif flag == /\z/
84
- :append
85
- else
86
- :insert
87
- end
78
+ def say_status(behavior)
79
+ status = if behavior == :invoke
80
+ if flag == /\A/
81
+ :prepend
82
+ elsif flag == /\z/
83
+ :append
88
84
  else
89
- :subtract
85
+ :insert
90
86
  end
91
-
92
- super(status, config[:verbose])
87
+ else
88
+ :subtract
93
89
  end
94
90
 
95
- # Adds the content to the file.
96
- #
97
- def replace!(regexp, string, force)
98
- unless base.options[:pretend]
99
- content = File.binread(destination)
100
- if force || !content.include?(replacement)
101
- content.gsub!(regexp, string)
102
- File.open(destination, 'wb') { |file| file.write(content) }
103
- end
91
+ super(status, config[:verbose])
92
+ end
93
+
94
+ # Adds the content to the file.
95
+ #
96
+ def replace!(regexp, string, force)
97
+ unless base.options[:pretend]
98
+ content = File.binread(destination)
99
+ if force || !content.include?(replacement)
100
+ content.gsub!(regexp, string)
101
+ File.open(destination, "wb") { |file| file.write(content) }
104
102
  end
105
103
  end
106
-
104
+ end
107
105
  end
108
106
  end
109
107
  end
@@ -1,23 +1,26 @@
1
- require 'thor/command'
2
- require 'thor/core_ext/hash_with_indifferent_access'
3
- require 'thor/core_ext/ordered_hash'
4
- require 'thor/error'
5
- require 'thor/invocation'
6
- require 'thor/parser'
7
- require 'thor/shell'
8
- require 'thor/util'
1
+ require "thor/command"
2
+ require "thor/core_ext/hash_with_indifferent_access"
3
+ require "thor/core_ext/ordered_hash"
4
+ require "thor/error"
5
+ require "thor/invocation"
6
+ require "thor/parser"
7
+ require "thor/shell"
8
+ require "thor/line_editor"
9
+ require "thor/util"
9
10
 
10
11
  class Thor
11
- autoload :Actions, 'thor/actions'
12
- autoload :RakeCompat, 'thor/rake_compat'
13
- autoload :Group, 'thor/group'
12
+ autoload :Actions, "thor/actions"
13
+ autoload :RakeCompat, "thor/rake_compat"
14
+ autoload :Group, "thor/group"
14
15
 
15
16
  # Shortcuts for help.
16
- HELP_MAPPINGS = %w(-h -? --help -D)
17
+ HELP_MAPPINGS = %w[-h -? --help -D]
17
18
 
18
19
  # Thor methods that should not be overwritten by the user.
19
- THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
20
- action add_file create_file in_root inside run run_ruby_script)
20
+ THOR_RESERVED_WORDS = %w[invoke shell options behavior root destination_root relative_root
21
+ action add_file create_file in_root inside run run_ruby_script]
22
+
23
+ TEMPLATE_EXTNAME = ".tt"
21
24
 
22
25
  module Base
23
26
  attr_accessor :options, :parent_options, :args
@@ -38,7 +41,7 @@ class Thor
38
41
  #
39
42
  # config<Hash>:: Configuration for this Thor class.
40
43
  #
41
- def initialize(args=[], options={}, config={})
44
+ def initialize(args = [], local_options = {}, config = {}) # rubocop:disable MethodLength
42
45
  parse_options = self.class.class_options
43
46
 
44
47
  # The start method splits inbound arguments at the first argument
@@ -46,14 +49,14 @@ class Thor
46
49
  # new, passing in the two halves of the arguments Array as the
47
50
  # first two parameters.
48
51
 
49
- if options.is_a?(Array)
50
- command_options = config.delete(:command_options) # hook for start
51
- parse_options = parse_options.merge(command_options) if command_options
52
- array_options, hash_options = options, {}
52
+ command_options = config.delete(:command_options) # hook for start
53
+ parse_options = parse_options.merge(command_options) if command_options
54
+ if local_options.is_a?(Array)
55
+ array_options, hash_options = local_options, {}
53
56
  else
54
57
  # Handle the case where the class was explicitly instantiated
55
58
  # with pre-parsed options.
56
- array_options, hash_options = [], options
59
+ array_options, hash_options = [], local_options
57
60
  end
58
61
 
59
62
  # Let Thor::Options parse the options first, so it can remove
@@ -62,7 +65,7 @@ class Thor
62
65
  stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
63
66
  opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown)
64
67
  self.options = opts.parse(array_options)
65
- self.options = config[:class_options].merge(self.options) if config[:class_options]
68
+ self.options = config[:class_options].merge(options) if config[:class_options]
66
69
 
67
70
  # If unknown options are disallowed, make sure that none of the
68
71
  # remaining arguments looks like an option.
@@ -77,13 +80,13 @@ class Thor
77
80
  to_parse += opts.remaining unless self.class.strict_args_position?(config)
78
81
 
79
82
  thor_args = Thor::Arguments.new(self.class.arguments)
80
- thor_args.parse(to_parse).each { |k,v| __send__("#{k}=", v) }
83
+ thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) }
81
84
  @args = thor_args.remaining
82
85
  end
83
86
 
84
87
  class << self
85
88
  def included(base) #:nodoc:
86
- base.send :extend, ClassMethods
89
+ base.extend ClassMethods
87
90
  base.send :include, Invocation
88
91
  base.send :include, Shell
89
92
  end
@@ -103,7 +106,7 @@ class Thor
103
106
  # Hash[path<String> => Class]
104
107
  #
105
108
  def subclass_files
106
- @subclass_files ||= Hash.new{ |h,k| h[k] = [] }
109
+ @subclass_files ||= Hash.new { |h, k| h[k] = [] }
107
110
  end
108
111
 
109
112
  # Whenever a class inherits from Thor or Thor::Group, we should track the
@@ -202,7 +205,7 @@ class Thor
202
205
  # ==== Errors
203
206
  # ArgumentError:: Raised if you supply a required argument after a non required one.
204
207
  #
205
- def argument(name, options={})
208
+ def argument(name, options = {}) # rubocop:disable MethodLength
206
209
  is_thor_reserved_word?(name, :argument)
207
210
  no_commands { attr_accessor name }
208
211
 
@@ -218,7 +221,7 @@ class Thor
218
221
 
219
222
  arguments.each do |argument|
220
223
  next if argument.required?
221
- raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
224
+ fail ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
222
225
  "the non-required argument #{argument.human_name.inspect}."
223
226
  end if required
224
227
 
@@ -245,7 +248,7 @@ class Thor
245
248
  # ==== Parameters
246
249
  # Hash[Symbol => Object]
247
250
  #
248
- def class_options(options=nil)
251
+ def class_options(options = nil)
249
252
  @class_options ||= from_superclass(:class_options, {})
250
253
  build_options(options, @class_options) if options
251
254
  @class_options
@@ -267,7 +270,7 @@ class Thor
267
270
  # :banner:: -- String to show on usage notes.
268
271
  # :hide:: -- If you want to hide this option from the help.
269
272
  #
270
- def class_option(name, options={})
273
+ def class_option(name, options = {})
271
274
  build_option(name, options, class_options)
272
275
  end
273
276
 
@@ -313,12 +316,11 @@ class Thor
313
316
  # ==== Parameters
314
317
  # name<String|Symbol>
315
318
  #
316
- def group(name=nil)
317
- @group = case name
318
- when nil
319
- @group || from_superclass(:group, 'standard')
319
+ def group(name = nil)
320
+ if name
321
+ @group = name.to_s
320
322
  else
321
- name.to_s
323
+ @group ||= from_superclass(:group, "standard")
322
324
  end
323
325
  end
324
326
 
@@ -331,7 +333,7 @@ class Thor
331
333
  def commands
332
334
  @commands ||= Thor::CoreExt::OrderedHash.new
333
335
  end
334
- alias tasks commands
336
+ alias_method :tasks, :commands
335
337
 
336
338
  # Returns the commands for this Thor class and all subclasses.
337
339
  #
@@ -343,7 +345,7 @@ class Thor
343
345
  @all_commands ||= from_superclass(:all_commands, Thor::CoreExt::OrderedHash.new)
344
346
  @all_commands.merge(commands)
345
347
  end
346
- alias all_tasks all_commands
348
+ alias_method :all_tasks, :all_commands
347
349
 
348
350
  # Removes a given command from this Thor class. This is usually done if you
349
351
  # are inheriting from another class and don't want it to be available
@@ -366,7 +368,7 @@ class Thor
366
368
  undef_method name if options[:undefine]
367
369
  end
368
370
  end
369
- alias remove_task remove_command
371
+ alias_method :remove_task, :remove_command
370
372
 
371
373
  # All methods defined inside the given block are not added as commands.
372
374
  #
@@ -393,7 +395,7 @@ class Thor
393
395
  ensure
394
396
  @no_commands = false
395
397
  end
396
- alias no_tasks no_commands
398
+ alias_method :no_tasks, :no_commands
397
399
 
398
400
  # Sets the namespace for the Thor or Thor::Group class. By default the
399
401
  # namespace is retrieved from the class name. If your Thor class is named
@@ -417,12 +419,11 @@ class Thor
417
419
  #
418
420
  # thor :my_command
419
421
  #
420
- def namespace(name=nil)
421
- @namespace = case name
422
- when nil
423
- @namespace || Thor::Util.namespace_from_thor_class(self)
424
- else
422
+ def namespace(name = nil)
423
+ if name
425
424
  @namespace = name.to_s
425
+ else
426
+ @namespace ||= Thor::Util.namespace_from_thor_class(self)
426
427
  end
427
428
  end
428
429
 
@@ -434,11 +435,11 @@ class Thor
434
435
  # script = MyScript.new(args, options, config)
435
436
  # script.invoke(:command, first_arg, second_arg, third_arg)
436
437
  #
437
- def start(given_args=ARGV, config={})
438
+ def start(given_args = ARGV, config = {})
438
439
  config[:shell] ||= Thor::Base.shell.new
439
440
  dispatch(nil, given_args.dup, nil, config)
440
441
  rescue Thor::Error => e
441
- ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
442
+ config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
442
443
  exit(1) if exit_on_failure?
443
444
  rescue Errno::EPIPE
444
445
  # This happens if a thor command is piped to something like `head`,
@@ -463,190 +464,193 @@ class Thor
463
464
  class_eval "def #{name}(*); super end"
464
465
  end
465
466
  end
466
- alias public_task public_command
467
+ alias_method :public_task, :public_command
467
468
 
468
469
  def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
469
470
  if has_namespace
470
- raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace."
471
+ fail UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace."
471
472
  else
472
- raise UndefinedCommandError, "Could not find command #{command.inspect}."
473
+ fail UndefinedCommandError, "Could not find command #{command.inspect}."
473
474
  end
474
475
  end
475
- alias handle_no_task_error handle_no_command_error
476
+ alias_method :handle_no_task_error, :handle_no_command_error
476
477
 
477
478
  def handle_argument_error(command, error, args, arity) #:nodoc:
478
- msg = "ERROR: #{basename} #{command.name} was called with "
479
- msg << 'no arguments' if args.empty?
480
- msg << 'arguments ' << args.inspect if !args.empty?
481
- msg << "\nUsage: #{self.banner(command).inspect}."
482
- raise InvocationError, msg
483
- end
484
-
485
- protected
486
-
487
- # Prints the class options per group. If an option does not belong to
488
- # any group, it's printed as Class option.
489
- #
490
- def class_options_help(shell, groups={}) #:nodoc:
491
- # Group options by group
492
- class_options.each do |_, value|
493
- groups[value.group] ||= []
494
- groups[value.group] << value
495
- end
479
+ msg = "ERROR: \"#{basename} #{command.name}\" was called with "
480
+ msg << "no arguments" if args.empty?
481
+ msg << "arguments " << args.inspect unless args.empty?
482
+ msg << "\nUsage: #{banner(command).inspect}"
483
+ fail InvocationError, msg
484
+ end
496
485
 
497
- # Deal with default group
498
- global_options = groups.delete(nil) || []
499
- print_options(shell, global_options)
486
+ protected
500
487
 
501
- # Print all others
502
- groups.each do |group_name, options|
503
- print_options(shell, options, group_name)
504
- end
488
+ # Prints the class options per group. If an option does not belong to
489
+ # any group, it's printed as Class option.
490
+ #
491
+ def class_options_help(shell, groups = {}) #:nodoc:
492
+ # Group options by group
493
+ class_options.each do |_, value|
494
+ groups[value.group] ||= []
495
+ groups[value.group] << value
505
496
  end
506
497
 
507
- # Receives a set of options and print them.
508
- def print_options(shell, options, group_name=nil)
509
- return if options.empty?
498
+ # Deal with default group
499
+ global_options = groups.delete(nil) || []
500
+ print_options(shell, global_options)
510
501
 
511
- list = []
512
- padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
502
+ # Print all others
503
+ groups.each do |group_name, options|
504
+ print_options(shell, options, group_name)
505
+ end
506
+ end
513
507
 
514
- options.each do |option|
515
- unless option.hide
516
- item = [ option.usage(padding) ]
517
- item.push(option.description ? "# #{option.description}" : "")
508
+ # Receives a set of options and print them.
509
+ def print_options(shell, options, group_name = nil)
510
+ return if options.empty?
518
511
 
519
- list << item
520
- list << [ "", "# Default: #{option.default}" ] if option.show_default?
521
- list << [ "", "# Possible values: #{option.enum.join(', ')}" ] if option.enum
522
- end
523
- end
512
+ list = []
513
+ padding = options.map { |o| o.aliases.size }.max.to_i * 4
524
514
 
525
- shell.say(group_name ? "#{group_name} options:" : "Options:")
526
- shell.print_table(list, :indent => 2)
527
- shell.say ""
528
- end
515
+ options.each do |option|
516
+ unless option.hide
517
+ item = [option.usage(padding)]
518
+ item.push(option.description ? "# #{option.description}" : "")
529
519
 
530
- # Raises an error if the word given is a Thor reserved word.
531
- def is_thor_reserved_word?(word, type) #:nodoc:
532
- return false unless THOR_RESERVED_WORDS.include?(word.to_s)
533
- raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
520
+ list << item
521
+ list << ["", "# Default: #{option.default}"] if option.show_default?
522
+ list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum
523
+ end
534
524
  end
535
525
 
536
- # Build an option and adds it to the given scope.
537
- #
538
- # ==== Parameters
539
- # name<Symbol>:: The name of the argument.
540
- # options<Hash>:: Described in both class_option and method_option.
541
- # scope<Hash>:: Options hash that is being built up
542
- def build_option(name, options, scope) #:nodoc:
543
- scope[name] = Thor::Option.new(name, options)
544
- end
526
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
527
+ shell.print_table(list, :indent => 2)
528
+ shell.say ""
529
+ end
545
530
 
546
- # Receives a hash of options, parse them and add to the scope. This is a
547
- # fast way to set a bunch of options:
548
- #
549
- # build_options :foo => true, :bar => :required, :baz => :string
550
- #
551
- # ==== Parameters
552
- # Hash[Symbol => Object]
553
- def build_options(options, scope) #:nodoc:
554
- options.each do |key, value|
555
- scope[key] = Thor::Option.parse(key, value)
556
- end
557
- end
531
+ # Raises an error if the word given is a Thor reserved word.
532
+ def is_thor_reserved_word?(word, type) #:nodoc:
533
+ return false unless THOR_RESERVED_WORDS.include?(word.to_s)
534
+ fail "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
535
+ end
558
536
 
559
- # Finds a command with the given name. If the command belongs to the current
560
- # class, just return it, otherwise dup it and add the fresh copy to the
561
- # current command hash.
562
- def find_and_refresh_command(name) #:nodoc:
563
- command = if command = commands[name.to_s]
564
- command
565
- elsif command = all_commands[name.to_s]
566
- commands[name.to_s] = command.clone
567
- else
568
- raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
569
- end
537
+ # Build an option and adds it to the given scope.
538
+ #
539
+ # ==== Parameters
540
+ # name<Symbol>:: The name of the argument.
541
+ # options<Hash>:: Described in both class_option and method_option.
542
+ # scope<Hash>:: Options hash that is being built up
543
+ def build_option(name, options, scope) #:nodoc:
544
+ scope[name] = Thor::Option.new(name, options)
545
+ end
546
+
547
+ # Receives a hash of options, parse them and add to the scope. This is a
548
+ # fast way to set a bunch of options:
549
+ #
550
+ # build_options :foo => true, :bar => :required, :baz => :string
551
+ #
552
+ # ==== Parameters
553
+ # Hash[Symbol => Object]
554
+ def build_options(options, scope) #:nodoc:
555
+ options.each do |key, value|
556
+ scope[key] = Thor::Option.parse(key, value)
570
557
  end
571
- alias find_and_refresh_task find_and_refresh_command
558
+ end
572
559
 
573
- # Everytime someone inherits from a Thor class, register the klass
574
- # and file into baseclass.
575
- def inherited(klass)
576
- Thor::Base.register_klass_file(klass)
577
- klass.instance_variable_set(:@no_commands, false)
560
+ # Finds a command with the given name. If the command belongs to the current
561
+ # class, just return it, otherwise dup it and add the fresh copy to the
562
+ # current command hash.
563
+ def find_and_refresh_command(name) #:nodoc:
564
+ if commands[name.to_s]
565
+ commands[name.to_s]
566
+ elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
567
+ commands[name.to_s] = command.clone
568
+ else
569
+ fail ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
578
570
  end
571
+ end
572
+ alias_method :find_and_refresh_task, :find_and_refresh_command
579
573
 
580
- # Fire this callback whenever a method is added. Added methods are
581
- # tracked as commands by invoking the create_command method.
582
- def method_added(meth)
583
- meth = meth.to_s
574
+ # Everytime someone inherits from a Thor class, register the klass
575
+ # and file into baseclass.
576
+ def inherited(klass)
577
+ Thor::Base.register_klass_file(klass)
578
+ klass.instance_variable_set(:@no_commands, false)
579
+ end
584
580
 
585
- if meth == "initialize"
586
- initialize_added
587
- return
588
- end
581
+ # Fire this callback whenever a method is added. Added methods are
582
+ # tracked as commands by invoking the create_command method.
583
+ def method_added(meth)
584
+ meth = meth.to_s
589
585
 
590
- # Return if it's not a public instance method
591
- return unless public_method_defined?(meth.to_sym)
586
+ if meth == "initialize"
587
+ initialize_added
588
+ return
589
+ end
592
590
 
593
- return if @no_commands || !create_command(meth)
591
+ # Return if it's not a public instance method
592
+ return unless public_method_defined?(meth.to_sym)
594
593
 
595
- is_thor_reserved_word?(meth, :command)
596
- Thor::Base.register_klass_file(self)
597
- end
594
+ @no_commands ||= false
595
+ return if @no_commands || !create_command(meth)
598
596
 
599
- # Retrieves a value from superclass. If it reaches the baseclass,
600
- # returns default.
601
- def from_superclass(method, default=nil)
602
- if self == baseclass || !superclass.respond_to?(method, true)
603
- default
604
- else
605
- value = superclass.send(method)
606
-
607
- if value
608
- if value.is_a?(TrueClass) || value.is_a?(Symbol)
609
- value
610
- else
611
- value.dup
612
- end
613
- end
597
+ is_thor_reserved_word?(meth, :command)
598
+ Thor::Base.register_klass_file(self)
599
+ end
600
+
601
+ # Retrieves a value from superclass. If it reaches the baseclass,
602
+ # returns default.
603
+ def from_superclass(method, default = nil)
604
+ if self == baseclass || !superclass.respond_to?(method, true)
605
+ default
606
+ else
607
+ value = superclass.send(method)
608
+
609
+ # Ruby implements `dup` on Object, but raises a `TypeError`
610
+ # if the method is called on immediates. As a result, we
611
+ # don't have a good way to check whether dup will succeed
612
+ # without calling it and rescuing the TypeError.
613
+ begin
614
+ value.dup
615
+ rescue TypeError
616
+ value
614
617
  end
615
- end
616
618
 
617
- # A flag that makes the process exit with status 1 if any error happens.
618
- def exit_on_failure?
619
- false
620
619
  end
620
+ end
621
621
 
622
- #
623
- # The basename of the program invoking the thor class.
624
- #
625
- def basename
626
- File.basename($0).split(' ').first
627
- end
622
+ # A flag that makes the process exit with status 1 if any error happens.
623
+ def exit_on_failure?
624
+ false
625
+ end
628
626
 
629
- # SIGNATURE: Sets the baseclass. This is where the superclass lookup
630
- # finishes.
631
- def baseclass #:nodoc:
632
- end
627
+ #
628
+ # The basename of the program invoking the thor class.
629
+ #
630
+ def basename
631
+ File.basename($PROGRAM_NAME).split(" ").first
632
+ end
633
633
 
634
- # SIGNATURE: Creates a new command if valid_command? is true. This method is
635
- # called when a new method is added to the class.
636
- def create_command(meth) #:nodoc:
637
- end
638
- alias create_task create_command
634
+ # SIGNATURE: Sets the baseclass. This is where the superclass lookup
635
+ # finishes.
636
+ def baseclass #:nodoc:
637
+ end
639
638
 
640
- # SIGNATURE: Defines behavior when the initialize method is added to the
641
- # class.
642
- def initialize_added #:nodoc:
643
- end
639
+ # SIGNATURE: Creates a new command if valid_command? is true. This method is
640
+ # called when a new method is added to the class.
641
+ def create_command(meth) #:nodoc:
642
+ end
643
+ alias_method :create_task, :create_command
644
644
 
645
- # SIGNATURE: The hook invoked by start.
646
- def dispatch(command, given_args, given_opts, config) #:nodoc:
647
- raise NotImplementedError
648
- end
645
+ # SIGNATURE: Defines behavior when the initialize method is added to the
646
+ # class.
647
+ def initialize_added #:nodoc:
648
+ end
649
649
 
650
+ # SIGNATURE: The hook invoked by start.
651
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
652
+ fail NotImplementedError
653
+ end
650
654
  end
651
655
  end
652
656
  end