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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +15 -0
  3. data/README.md +23 -6
  4. data/bin/thor +1 -1
  5. data/lib/thor/actions/create_file.rb +34 -35
  6. data/lib/thor/actions/create_link.rb +9 -5
  7. data/lib/thor/actions/directory.rb +33 -23
  8. data/lib/thor/actions/empty_directory.rb +75 -85
  9. data/lib/thor/actions/file_manipulation.rb +103 -36
  10. data/lib/thor/actions/inject_into_file.rb +46 -36
  11. data/lib/thor/actions.rb +90 -68
  12. data/lib/thor/base.rb +302 -244
  13. data/lib/thor/command.rb +142 -0
  14. data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
  15. data/lib/thor/error.rb +90 -10
  16. data/lib/thor/group.rb +70 -74
  17. data/lib/thor/invocation.rb +63 -55
  18. data/lib/thor/line_editor/basic.rb +37 -0
  19. data/lib/thor/line_editor/readline.rb +88 -0
  20. data/lib/thor/line_editor.rb +17 -0
  21. data/lib/thor/nested_context.rb +29 -0
  22. data/lib/thor/parser/argument.rb +24 -28
  23. data/lib/thor/parser/arguments.rb +110 -102
  24. data/lib/thor/parser/option.rb +53 -15
  25. data/lib/thor/parser/options.rb +174 -97
  26. data/lib/thor/parser.rb +4 -4
  27. data/lib/thor/rake_compat.rb +12 -11
  28. data/lib/thor/runner.rb +159 -155
  29. data/lib/thor/shell/basic.rb +216 -93
  30. data/lib/thor/shell/color.rb +53 -40
  31. data/lib/thor/shell/html.rb +61 -58
  32. data/lib/thor/shell.rb +29 -36
  33. data/lib/thor/util.rb +231 -213
  34. data/lib/thor/version.rb +1 -1
  35. data/lib/thor.rb +303 -166
  36. data/thor.gemspec +27 -24
  37. metadata +36 -226
  38. data/.gitignore +0 -44
  39. data/.rspec +0 -2
  40. data/.travis.yml +0 -7
  41. data/CHANGELOG.rdoc +0 -134
  42. data/Gemfile +0 -15
  43. data/Thorfile +0 -30
  44. data/bin/rake2thor +0 -86
  45. data/lib/thor/core_ext/dir_escape.rb +0 -0
  46. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  47. data/lib/thor/core_ext/ordered_hash.rb +0 -100
  48. data/lib/thor/task.rb +0 -132
  49. data/spec/actions/create_file_spec.rb +0 -170
  50. data/spec/actions/create_link_spec.rb +0 -81
  51. data/spec/actions/directory_spec.rb +0 -149
  52. data/spec/actions/empty_directory_spec.rb +0 -130
  53. data/spec/actions/file_manipulation_spec.rb +0 -370
  54. data/spec/actions/inject_into_file_spec.rb +0 -135
  55. data/spec/actions_spec.rb +0 -331
  56. data/spec/base_spec.rb +0 -279
  57. data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
  58. data/spec/core_ext/ordered_hash_spec.rb +0 -115
  59. data/spec/exit_condition_spec.rb +0 -19
  60. data/spec/fixtures/application.rb +0 -2
  61. data/spec/fixtures/app{1}/README +0 -3
  62. data/spec/fixtures/bundle/execute.rb +0 -6
  63. data/spec/fixtures/bundle/main.thor +0 -1
  64. data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
  65. data/spec/fixtures/doc/COMMENTER +0 -10
  66. data/spec/fixtures/doc/README +0 -3
  67. data/spec/fixtures/doc/block_helper.rb +0 -3
  68. data/spec/fixtures/doc/components/.empty_directory +0 -0
  69. data/spec/fixtures/doc/config.rb +0 -1
  70. data/spec/fixtures/doc/config.yaml.tt +0 -1
  71. data/spec/fixtures/enum.thor +0 -10
  72. data/spec/fixtures/group.thor +0 -114
  73. data/spec/fixtures/invoke.thor +0 -112
  74. data/spec/fixtures/path with spaces +0 -0
  75. data/spec/fixtures/script.thor +0 -190
  76. data/spec/fixtures/task.thor +0 -10
  77. data/spec/group_spec.rb +0 -216
  78. data/spec/invocation_spec.rb +0 -100
  79. data/spec/parser/argument_spec.rb +0 -53
  80. data/spec/parser/arguments_spec.rb +0 -66
  81. data/spec/parser/option_spec.rb +0 -202
  82. data/spec/parser/options_spec.rb +0 -330
  83. data/spec/rake_compat_spec.rb +0 -72
  84. data/spec/register_spec.rb +0 -135
  85. data/spec/runner_spec.rb +0 -241
  86. data/spec/shell/basic_spec.rb +0 -300
  87. data/spec/shell/color_spec.rb +0 -81
  88. data/spec/shell/html_spec.rb +0 -32
  89. data/spec/shell_spec.rb +0 -47
  90. data/spec/spec_helper.rb +0 -59
  91. data/spec/task_spec.rb +0 -80
  92. data/spec/thor_spec.rb +0 -418
  93. data/spec/util_spec.rb +0 -196
@@ -0,0 +1,142 @@
1
+ class Thor
2
+ class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name)
3
+ FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
4
+
5
+ def initialize(name, description, long_description, usage, options = nil)
6
+ super(name.to_s, description, long_description, usage, options || {})
7
+ end
8
+
9
+ def initialize_copy(other) #:nodoc:
10
+ super(other)
11
+ self.options = other.options.dup if other.options
12
+ end
13
+
14
+ def hidden?
15
+ false
16
+ end
17
+
18
+ # By default, a command invokes a method in the thor class. You can change this
19
+ # implementation to create custom commands.
20
+ def run(instance, args = [])
21
+ arity = nil
22
+
23
+ if private_method?(instance)
24
+ instance.class.handle_no_command_error(name)
25
+ elsif public_method?(instance)
26
+ arity = instance.method(name).arity
27
+ instance.__send__(name, *args)
28
+ elsif local_method?(instance, :method_missing)
29
+ instance.__send__(:method_missing, name.to_sym, *args)
30
+ else
31
+ instance.class.handle_no_command_error(name)
32
+ end
33
+ rescue ArgumentError => e
34
+ handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e)
35
+ rescue NoMethodError => e
36
+ handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e)
37
+ end
38
+
39
+ # Returns the formatted usage by injecting given required arguments
40
+ # and required options into the given usage.
41
+ def formatted_usage(klass, namespace = true, subcommand = false)
42
+ if ancestor_name
43
+ formatted = "#{ancestor_name} ".dup # add space
44
+ elsif namespace
45
+ namespace = klass.namespace
46
+ formatted = "#{namespace.gsub(/^(default)/, '')}:".dup
47
+ end
48
+ formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand
49
+
50
+ formatted ||= "".dup
51
+
52
+ Array(usage).map do |specific_usage|
53
+ formatted_specific_usage = formatted
54
+
55
+ formatted_specific_usage += required_arguments_for(klass, specific_usage)
56
+
57
+ # Add required options
58
+ formatted_specific_usage += " #{required_options}"
59
+
60
+ # Strip and go!
61
+ formatted_specific_usage.strip
62
+ end.join("\n")
63
+ end
64
+
65
+ protected
66
+
67
+ # Add usage with required arguments
68
+ def required_arguments_for(klass, usage)
69
+ if klass && !klass.arguments.empty?
70
+ usage.to_s.gsub(/^#{name}/) do |match|
71
+ match << " " << klass.arguments.map(&:usage).compact.join(" ")
72
+ end
73
+ else
74
+ usage.to_s
75
+ end
76
+ end
77
+
78
+ def not_debugging?(instance)
79
+ !(instance.class.respond_to?(:debugging) && instance.class.debugging)
80
+ end
81
+
82
+ def required_options
83
+ @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ")
84
+ end
85
+
86
+ # Given a target, checks if this class name is a public method.
87
+ def public_method?(instance) #:nodoc:
88
+ !(instance.public_methods & [name.to_s, name.to_sym]).empty?
89
+ end
90
+
91
+ def private_method?(instance)
92
+ !(instance.private_methods & [name.to_s, name.to_sym]).empty?
93
+ end
94
+
95
+ def local_method?(instance, name)
96
+ methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
97
+ !(methods & [name.to_s, name.to_sym]).empty?
98
+ end
99
+
100
+ def sans_backtrace(backtrace, caller) #:nodoc:
101
+ saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) }
102
+ saned - caller
103
+ end
104
+
105
+ def handle_argument_error?(instance, error, caller)
106
+ not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin
107
+ saned = sans_backtrace(error.backtrace, caller)
108
+ saned.empty? || saned.size == 1
109
+ end
110
+ end
111
+
112
+ def handle_no_method_error?(instance, error, caller)
113
+ not_debugging?(instance) &&
114
+ error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
115
+ end
116
+ end
117
+ Task = Command
118
+
119
+ # A command that is hidden in help messages but still invocable.
120
+ class HiddenCommand < Command
121
+ def hidden?
122
+ true
123
+ end
124
+ end
125
+ HiddenTask = HiddenCommand
126
+
127
+ # A dynamic command that handles method missing scenarios.
128
+ class DynamicCommand < Command
129
+ def initialize(name, options = nil)
130
+ super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
131
+ end
132
+
133
+ def run(instance, args = [])
134
+ if (instance.methods & [name.to_s, name.to_sym]).empty?
135
+ super
136
+ else
137
+ instance.class.handle_no_command_error(name)
138
+ end
139
+ end
140
+ end
141
+ DynamicTask = DynamicCommand
142
+ end
@@ -1,6 +1,5 @@
1
1
  class Thor
2
2
  module CoreExt #:nodoc:
3
-
4
3
  # A hash with indifferent access and magic predicates.
5
4
  #
6
5
  # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
@@ -10,8 +9,7 @@ class Thor
10
9
  # hash.foo? #=> true
11
10
  #
12
11
  class HashWithIndifferentAccess < ::Hash #:nodoc:
13
-
14
- def initialize(hash={})
12
+ def initialize(hash = {})
15
13
  super()
16
14
  hash.each do |key, value|
17
15
  self[convert_key(key)] = value
@@ -30,8 +28,22 @@ class Thor
30
28
  super(convert_key(key))
31
29
  end
32
30
 
31
+ def except(*keys)
32
+ dup.tap do |hash|
33
+ keys.each { |key| hash.delete(convert_key(key)) }
34
+ end
35
+ end
36
+
37
+ def fetch(key, *args)
38
+ super(convert_key(key), *args)
39
+ end
40
+
41
+ def key?(key)
42
+ super(convert_key(key))
43
+ end
44
+
33
45
  def values_at(*indices)
34
- indices.collect { |key| self[convert_key(key)] }
46
+ indices.map { |key| self[convert_key(key)] }
35
47
  end
36
48
 
37
49
  def merge(other)
@@ -45,31 +57,47 @@ class Thor
45
57
  self
46
58
  end
47
59
 
48
- protected
60
+ def reverse_merge(other)
61
+ self.class.new(other).merge(self)
62
+ end
63
+
64
+ def reverse_merge!(other_hash)
65
+ replace(reverse_merge(other_hash))
66
+ end
49
67
 
50
- def convert_key(key)
51
- key.is_a?(Symbol) ? key.to_s : key
52
- end
68
+ def replace(other_hash)
69
+ super(other_hash)
70
+ end
71
+
72
+ # Convert to a Hash with String keys.
73
+ def to_hash
74
+ Hash.new(default).merge!(self)
75
+ end
53
76
 
54
- # Magic predicates. For instance:
55
- #
56
- # options.force? # => !!options['force']
57
- # options.shebang # => "/usr/lib/local/ruby"
58
- # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
59
- #
60
- def method_missing(method, *args, &block)
61
- method = method.to_s
62
- if method =~ /^(\w+)\?$/
63
- if args.empty?
64
- !!self[$1]
65
- else
66
- self[$1] == args.first
67
- end
77
+ protected
78
+
79
+ def convert_key(key)
80
+ key.is_a?(Symbol) ? key.to_s : key
81
+ end
82
+
83
+ # Magic predicates. For instance:
84
+ #
85
+ # options.force? # => !!options['force']
86
+ # options.shebang # => "/usr/lib/local/ruby"
87
+ # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
88
+ #
89
+ def method_missing(method, *args)
90
+ method = method.to_s
91
+ if method =~ /^(\w+)\?$/
92
+ if args.empty?
93
+ !!self[$1]
68
94
  else
69
- self[method]
95
+ self[$1] == args.first
70
96
  end
97
+ else
98
+ self[method]
71
99
  end
72
-
100
+ end
73
101
  end
74
102
  end
75
103
  end
data/lib/thor/error.rb CHANGED
@@ -1,25 +1,98 @@
1
1
  class Thor
2
+ Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName
3
+ # In order to support versions of Ruby that don't have keyword
4
+ # arguments, we need our own spell checker class that doesn't take key
5
+ # words. Even though this code wouldn't be hit because of the check
6
+ # above, it's still necessary because the interpreter would otherwise be
7
+ # unable to parse the file.
8
+ class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc:
9
+ def initialize(dictionary)
10
+ @dictionary = dictionary
11
+ end
12
+ end
13
+
14
+ DidYouMean::Correctable
15
+ end
16
+
2
17
  # Thor::Error is raised when it's caused by wrong usage of thor classes. Those
3
18
  # errors have their backtrace suppressed and are nicely shown to the user.
4
19
  #
5
20
  # Errors that are caused by the developer, like declaring a method which
6
- # overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
21
+ # overwrites a thor keyword, SHOULD NOT raise a Thor::Error. This way, we
7
22
  # ensure that developer errors are shown with full backtrace.
8
- #
9
23
  class Error < StandardError
10
24
  end
11
25
 
12
- # Raised when a task was not found.
13
- #
14
- class UndefinedTaskError < Error
26
+ # Raised when a command was not found.
27
+ class UndefinedCommandError < Error
28
+ class SpellChecker
29
+ attr_reader :error
30
+
31
+ def initialize(error)
32
+ @error = error
33
+ end
34
+
35
+ def corrections
36
+ @corrections ||= spell_checker.correct(error.command).map(&:inspect)
37
+ end
38
+
39
+ def spell_checker
40
+ NoKwargSpellChecker.new(error.all_commands)
41
+ end
42
+ end
43
+
44
+ attr_reader :command, :all_commands
45
+
46
+ def initialize(command, all_commands, namespace)
47
+ @command = command
48
+ @all_commands = all_commands
49
+
50
+ message = "Could not find command #{command.inspect}"
51
+ message = namespace ? "#{message} in #{namespace.inspect} namespace." : "#{message}."
52
+
53
+ super(message)
54
+ end
55
+
56
+ prepend Correctable if Correctable
15
57
  end
58
+ UndefinedTaskError = UndefinedCommandError
16
59
 
17
- # Raised when a task was found, but not invoked properly.
18
- #
60
+ class AmbiguousCommandError < Error
61
+ end
62
+ AmbiguousTaskError = AmbiguousCommandError
63
+
64
+ # Raised when a command was found, but not invoked properly.
19
65
  class InvocationError < Error
20
66
  end
21
67
 
22
68
  class UnknownArgumentError < Error
69
+ class SpellChecker
70
+ attr_reader :error
71
+
72
+ def initialize(error)
73
+ @error = error
74
+ end
75
+
76
+ def corrections
77
+ @corrections ||=
78
+ error.unknown.flat_map { |unknown| spell_checker.correct(unknown) }.uniq.map(&:inspect)
79
+ end
80
+
81
+ def spell_checker
82
+ @spell_checker ||= NoKwargSpellChecker.new(error.switches)
83
+ end
84
+ end
85
+
86
+ attr_reader :switches, :unknown
87
+
88
+ def initialize(switches, unknown)
89
+ @switches = switches
90
+ @unknown = unknown
91
+
92
+ super("Unknown switches #{unknown.map(&:inspect).join(', ')}")
93
+ end
94
+
95
+ prepend Correctable if Correctable
23
96
  end
24
97
 
25
98
  class RequiredArgumentMissingError < InvocationError
@@ -28,8 +101,15 @@ class Thor
28
101
  class MalformattedArgumentError < InvocationError
29
102
  end
30
103
 
31
- # Raised when a user tries to call a private method encoded in templated filename.
32
- #
33
- class PrivateMethodEncodedError < Error
104
+ if Correctable
105
+ if DidYouMean.respond_to?(:correct_error)
106
+ DidYouMean.correct_error(Thor::UndefinedCommandError, UndefinedCommandError::SpellChecker)
107
+ DidYouMean.correct_error(Thor::UnknownArgumentError, UnknownArgumentError::SpellChecker)
108
+ else
109
+ DidYouMean::SPELL_CHECKERS.merge!(
110
+ 'Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker,
111
+ 'Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker
112
+ )
113
+ end
34
114
  end
35
115
  end
data/lib/thor/group.rb CHANGED
@@ -1,9 +1,9 @@
1
- require 'thor/base'
1
+ require_relative "base"
2
2
 
3
3
  # Thor has a special class called Thor::Group. The main difference to Thor class
4
- # is that it invokes all tasks at once. It also include some methods that allows
4
+ # is that it invokes all commands at once. It also include some methods that allows
5
5
  # invocations to be done at the class method, which are not available to Thor
6
- # tasks.
6
+ # commands.
7
7
  class Thor::Group
8
8
  class << self
9
9
  # The description for this Thor::Group. If none is provided, but a source root
@@ -13,12 +13,11 @@ class Thor::Group
13
13
  # ==== Parameters
14
14
  # description<String>:: The description for this Thor::Group.
15
15
  #
16
- def desc(description=nil)
17
- case description
18
- when nil
19
- @desc ||= from_superclass(:desc, nil)
20
- else
21
- @desc = description
16
+ def desc(description = nil)
17
+ if description
18
+ @desc = description
19
+ else
20
+ @desc ||= from_superclass(:desc, nil)
22
21
  end
23
22
  end
24
23
 
@@ -32,7 +31,7 @@ class Thor::Group
32
31
  shell.say " #{banner}\n"
33
32
  shell.say
34
33
  class_options_help(shell)
35
- shell.say self.desc if self.desc
34
+ shell.say desc if desc
36
35
  end
37
36
 
38
37
  # Stores invocations for this class merging with superclass values.
@@ -48,7 +47,7 @@ class Thor::Group
48
47
  end
49
48
 
50
49
  # Invoke the given namespace or class given. It adds an instance
51
- # method that will invoke the klass and task. You can give a block to
50
+ # method that will invoke the klass and command. You can give a block to
52
51
  # configure how it will be invoked.
53
52
  #
54
53
  # The namespace/class given will have its options showed on the help
@@ -62,14 +61,14 @@ class Thor::Group
62
61
  invocations[name] = false
63
62
  invocation_blocks[name] = block if block_given?
64
63
 
65
- class_eval <<-METHOD, __FILE__, __LINE__
64
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
66
65
  def _invoke_#{name.to_s.gsub(/\W/, '_')}
67
- klass, task = self.class.prepare_for_invocation(nil, #{name.inspect})
66
+ klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
68
67
 
69
68
  if klass
70
69
  say_status :invoke, #{name.inspect}, #{verbose.inspect}
71
70
  block = self.class.invocation_blocks[#{name.inspect}]
72
- _invoke_for_class_method klass, task, &block
71
+ _invoke_for_class_method klass, command, &block
73
72
  else
74
73
  say_status :error, %(#{name.inspect} [not found]), :red
75
74
  end
@@ -100,7 +99,7 @@ class Thor::Group
100
99
  # In some cases you want to customize how a specified hook is going to be
101
100
  # invoked. You can do that by overwriting the class method
102
101
  # prepare_for_invocation. The class method must necessarily return a klass
103
- # and an optional task.
102
+ # and an optional command.
104
103
  #
105
104
  # ==== Custom invocations
106
105
  #
@@ -114,25 +113,25 @@ class Thor::Group
114
113
 
115
114
  names.each do |name|
116
115
  unless class_options.key?(name)
117
- raise ArgumentError, "You have to define the option #{name.inspect} " <<
118
- "before setting invoke_from_option."
116
+ raise ArgumentError, "You have to define the option #{name.inspect} " \
117
+ "before setting invoke_from_option."
119
118
  end
120
119
 
121
120
  invocations[name] = true
122
121
  invocation_blocks[name] = block if block_given?
123
122
 
124
- class_eval <<-METHOD, __FILE__, __LINE__
123
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
125
124
  def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
126
125
  return unless options[#{name.inspect}]
127
126
 
128
127
  value = options[#{name.inspect}]
129
128
  value = #{name.inspect} if TrueClass === value
130
- klass, task = self.class.prepare_for_invocation(#{name.inspect}, value)
129
+ klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
131
130
 
132
131
  if klass
133
132
  say_status :invoke, value, #{verbose.inspect}
134
133
  block = self.class.invocation_blocks[#{name.inspect}]
135
- _invoke_for_class_method klass, task, &block
134
+ _invoke_for_class_method klass, command, &block
136
135
  else
137
136
  say_status :error, %(\#{value} [not found]), :red
138
137
  end
@@ -149,7 +148,7 @@ class Thor::Group
149
148
  #
150
149
  def remove_invocation(*names)
151
150
  names.each do |name|
152
- remove_task(name)
151
+ remove_command(name)
153
152
  remove_class_option(name)
154
153
  invocations.delete(name)
155
154
  invocation_blocks.delete(name)
@@ -159,7 +158,7 @@ class Thor::Group
159
158
  # Overwrite class options help to allow invoked generators options to be
160
159
  # shown recursively when invoking a generator.
161
160
  #
162
- def class_options_help(shell, groups={}) #:nodoc:
161
+ def class_options_help(shell, groups = {}) #:nodoc:
163
162
  get_options_from_invocations(groups, class_options) do |klass|
164
163
  klass.send(:get_options_from_invocations, groups, class_options)
165
164
  end
@@ -170,7 +169,7 @@ class Thor::Group
170
169
  # options are added to group_options hash. Options that already exists
171
170
  # in base_options are not added twice.
172
171
  #
173
- def get_options_from_invocations(group_options, base_options) #:nodoc:
172
+ def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
174
173
  invocations.each do |name, from_option|
175
174
  value = if from_option
176
175
  option = class_options[name]
@@ -189,96 +188,93 @@ class Thor::Group
189
188
  group_options[human_name] ||= []
190
189
  group_options[human_name] += klass.class_options.values.select do |class_option|
191
190
  base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
192
- !group_options.values.flatten.any? { |i| i.name == class_option.name }
191
+ !group_options.values.flatten.any? { |i| i.name == class_option.name }
193
192
  end
194
193
 
195
194
  yield klass if block_given?
196
195
  end
197
196
  end
198
197
 
199
- # Returns tasks ready to be printed.
200
- def printable_tasks(*)
198
+ # Returns commands ready to be printed.
199
+ def printable_commands(*)
201
200
  item = []
202
201
  item << banner
203
- item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
202
+ item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "")
204
203
  [item]
205
204
  end
205
+ alias_method :printable_tasks, :printable_commands
206
206
 
207
- def handle_argument_error(task, error, arity=nil) #:nodoc:
208
- if arity > 0
209
- msg = "#{basename} #{task.name} takes #{arity} argument"
210
- msg << "s" if arity > 1
211
- msg << ", but it should not."
212
- else
213
- msg = "You should not pass arguments to #{basename} #{task.name}."
214
- end
215
-
207
+ def handle_argument_error(command, error, _args, arity) #:nodoc:
208
+ msg = "#{basename} #{command.name} takes #{arity} argument".dup
209
+ msg << "s" if arity > 1
210
+ msg << ", but it should not."
216
211
  raise error, msg
217
212
  end
218
213
 
219
- protected
214
+ protected
220
215
 
221
- # The method responsible for dispatching given the args.
222
- def dispatch(task, given_args, given_opts, config) #:nodoc:
223
- if Thor::HELP_MAPPINGS.include?(given_args.first)
224
- help(config[:shell])
225
- return
226
- end
216
+ # The method responsible for dispatching given the args.
217
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
218
+ if Thor::HELP_MAPPINGS.include?(given_args.first)
219
+ help(config[:shell])
220
+ return
221
+ end
227
222
 
228
- args, opts = Thor::Options.split(given_args)
229
- opts = given_opts || opts
223
+ args, opts = Thor::Options.split(given_args)
224
+ opts = given_opts || opts
230
225
 
231
- instance = new(args, opts, config)
232
- yield instance if block_given?
233
- args = instance.args
226
+ instance = new(args, opts, config)
227
+ yield instance if block_given?
234
228
 
235
- if task
236
- instance.invoke_task(all_tasks[task])
237
- else
238
- instance.invoke_all
239
- end
229
+ if command
230
+ instance.invoke_command(all_commands[command])
231
+ else
232
+ instance.invoke_all
240
233
  end
234
+ end
241
235
 
242
- # The banner for this class. You can customize it if you are invoking the
243
- # thor class by another ways which is not the Thor::Runner.
244
- def banner
245
- "#{basename} #{self_task.formatted_usage(self, false)}"
246
- end
236
+ # The banner for this class. You can customize it if you are invoking the
237
+ # thor class by another ways which is not the Thor::Runner.
238
+ def banner
239
+ "#{basename} #{self_command.formatted_usage(self, false)}"
240
+ end
247
241
 
248
- # Represents the whole class as a task.
249
- def self_task #:nodoc:
250
- Thor::DynamicTask.new(self.namespace, class_options)
251
- end
242
+ # Represents the whole class as a command.
243
+ def self_command #:nodoc:
244
+ Thor::DynamicCommand.new(namespace, class_options)
245
+ end
246
+ alias_method :self_task, :self_command
252
247
 
253
- def baseclass #:nodoc:
254
- Thor::Group
255
- end
248
+ def baseclass #:nodoc:
249
+ Thor::Group
250
+ end
256
251
 
257
- def create_task(meth) #:nodoc:
258
- tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, nil)
259
- true
260
- end
252
+ def create_command(meth) #:nodoc:
253
+ commands[meth.to_s] = Thor::Command.new(meth, nil, nil, nil, nil)
254
+ true
255
+ end
256
+ alias_method :create_task, :create_command
261
257
  end
262
258
 
263
259
  include Thor::Base
264
260
 
265
- protected
261
+ protected
266
262
 
267
263
  # Shortcut to invoke with padding and block handling. Use internally by
268
264
  # invoke and invoke_from_option class methods.
269
- def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
265
+ def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc:
270
266
  with_padding do
271
267
  if block
272
268
  case block.arity
273
269
  when 3
274
- block.call(self, klass, task)
270
+ yield(self, klass, command)
275
271
  when 2
276
- block.call(self, klass)
272
+ yield(self, klass)
277
273
  when 1
278
274
  instance_exec(klass, &block)
279
275
  end
280
276
  else
281
- invoke klass, task, *args
277
+ invoke klass, command, *args
282
278
  end
283
279
  end
284
280
  end