thor 0.17.0 → 0.18.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 (70) hide show
  1. data/{CHANGELOG.rdoc → CHANGELOG.md} +30 -36
  2. data/README.md +10 -3
  3. data/lib/thor.rb +205 -180
  4. data/lib/thor/actions.rb +5 -5
  5. data/lib/thor/actions/create_link.rb +3 -0
  6. data/lib/thor/actions/directory.rb +2 -0
  7. data/lib/thor/actions/file_manipulation.rb +1 -1
  8. data/lib/thor/base.rb +84 -95
  9. data/lib/thor/{task.rb → command.rb} +17 -13
  10. data/lib/thor/core_ext/io_binary_read.rb +12 -0
  11. data/lib/thor/error.rb +4 -7
  12. data/lib/thor/group.rb +30 -33
  13. data/lib/thor/invocation.rb +28 -26
  14. data/lib/thor/parser/options.rb +3 -1
  15. data/lib/thor/runner.rb +21 -20
  16. data/lib/thor/shell/basic.rb +5 -1
  17. data/lib/thor/shell/color.rb +4 -0
  18. data/lib/thor/shell/html.rb +4 -0
  19. data/lib/thor/util.rb +214 -210
  20. data/lib/thor/version.rb +1 -1
  21. data/spec/actions/create_file_spec.rb +1 -1
  22. data/spec/actions/create_link_spec.rb +15 -1
  23. data/spec/actions/directory_spec.rb +18 -5
  24. data/spec/actions/empty_directory_spec.rb +1 -1
  25. data/spec/actions/file_manipulation_spec.rb +13 -13
  26. data/spec/actions/inject_into_file_spec.rb +1 -1
  27. data/spec/actions_spec.rb +1 -1
  28. data/spec/base_spec.rb +40 -24
  29. data/spec/command_spec.rb +80 -0
  30. data/spec/core_ext/hash_with_indifferent_access_spec.rb +1 -1
  31. data/spec/core_ext/ordered_hash_spec.rb +1 -1
  32. data/spec/exit_condition_spec.rb +3 -3
  33. data/spec/fixtures/{task.thor → command.thor} +0 -0
  34. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  35. data/spec/fixtures/doc/COMMENTER +11 -0
  36. data/spec/fixtures/doc/README +3 -0
  37. data/spec/fixtures/doc/block_helper.rb +3 -0
  38. data/spec/fixtures/doc/config.rb +1 -0
  39. data/spec/fixtures/doc/config.yaml.tt +1 -0
  40. data/spec/fixtures/doc/excluding/%file_name%.rb.tt +1 -0
  41. data/spec/fixtures/group.thor +24 -10
  42. data/spec/fixtures/invoke.thor +3 -3
  43. data/spec/fixtures/script.thor +40 -15
  44. data/spec/fixtures/subcommand.thor +17 -0
  45. data/spec/group_spec.rb +13 -13
  46. data/spec/{spec_helper.rb → helper.rb} +11 -7
  47. data/spec/invocation_spec.rb +16 -16
  48. data/spec/parser/argument_spec.rb +4 -4
  49. data/spec/parser/arguments_spec.rb +1 -1
  50. data/spec/parser/option_spec.rb +1 -1
  51. data/spec/parser/options_spec.rb +6 -1
  52. data/spec/rake_compat_spec.rb +1 -1
  53. data/spec/register_spec.rb +12 -12
  54. data/spec/runner_spec.rb +36 -36
  55. data/spec/shell/basic_spec.rb +9 -10
  56. data/spec/shell/color_spec.rb +16 -2
  57. data/spec/shell/html_spec.rb +1 -1
  58. data/spec/shell_spec.rb +1 -1
  59. data/spec/subcommand_spec.rb +30 -0
  60. data/spec/thor_spec.rb +81 -78
  61. data/spec/util_spec.rb +10 -10
  62. data/thor.gemspec +22 -18
  63. metadata +49 -38
  64. data/.gitignore +0 -44
  65. data/.rspec +0 -3
  66. data/.travis.yml +0 -8
  67. data/Gemfile +0 -19
  68. data/bin/rake2thor +0 -86
  69. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  70. data/spec/task_spec.rb +0 -80
@@ -1,4 +1,13 @@
1
- == 0.17.0, release 2013-01-24
1
+ ## 0.18.0, release 2013-03-26
2
+ * Remove rake2thor
3
+ * Only display colors if output medium supports colors
4
+ * Pass parent_options to subcommands
5
+ * Fix non-dash-prefixed aliases
6
+ * Make error messages more helpful
7
+ * Rename "task" to "command"
8
+ * Add the method to allow for custom package name
9
+
10
+ ## 0.17.0, release 2013-01-24
2
11
  * Add better support for tasks that accept arbitrary additional arguments (e.g. things like `bundle exec`)
3
12
  * Add #stop_on_unknown_option!
4
13
  * Only strip from stdin.gets if it wasn't ended with EOF
@@ -6,26 +15,26 @@
6
15
  * Allow passing options as arguments after "--"
7
16
  * Autoload Thor::Group
8
17
 
9
- == 0.16.0, release 2012-08-14
18
+ ## 0.16.0, release 2012-08-14
10
19
  * Add enum to string arguments
11
20
 
12
- == 0.15.4, release 2012-06-29
21
+ ## 0.15.4, release 2012-06-29
13
22
  * Fix regression when destination root contains reserved regexp characters
14
23
 
15
- == 0.15.3, release 2012-06-18
24
+ ## 0.15.3, release 2012-06-18
16
25
  * Support strict_args_position! for backwards compatibility
17
26
  * Escape Dir glob characters in paths
18
27
 
19
- == 0.15.2, released 2012-05-07
28
+ ## 0.15.2, released 2012-05-07
20
29
  * Added print_in_columns
21
30
  * Exposed terminal_width as a public API
22
31
 
23
- == 0.15.1, release 2012-05-06
32
+ ## 0.15.1, release 2012-05-06
24
33
  * Fix Ruby 1.8 truncation bug with unicode chars
25
34
  * Fix shell delegate methods to pass their block
26
35
  * Don't output trailing spaces when printing the last column in a table
27
36
 
28
- == 0.15, released 2012-04-29
37
+ ## 0.15, released 2012-04-29
29
38
  * Alias method_options to options
30
39
  * Refactor say to allow multiple colors
31
40
  * Exposed error as a public API
@@ -37,8 +46,7 @@
37
46
  * Fix Errno::EPIPE when piping tasks to `head`
38
47
  * More friendly error messages
39
48
 
40
- == 0.14, released 2010-07-25
41
-
49
+ ## 0.14, released 2010-07-25
42
50
  * Added CreateLink class and #link_file method
43
51
  * Made Thor::Actions#run use system as default method for system calls
44
52
  * Allow use of private methods from superclass as tasks
@@ -49,8 +57,7 @@
49
57
  * Deprecated invoke() without arguments
50
58
  * Added :only and :except to check_unknown_options
51
59
 
52
- == 0.13, released 2010-02-03
53
-
60
+ ## 0.13, released 2010-02-03
54
61
  * Added :lazy_default which is only triggered if a switch is given
55
62
  * Added Thor::Shell::HTML
56
63
  * Added subcommands
@@ -58,8 +65,7 @@
58
65
  * Added check_unknown_options! in case you want error messages to be raised in valid switches
59
66
  * run(command) should return the results of command
60
67
 
61
- == 0.12, released 2010-01-02
62
-
68
+ ## 0.12, released 2010-01-02
63
69
  * Methods generated by attr_* are automatically not marked as tasks
64
70
  * inject_into_file does not add the same content twice, unless :force is set
65
71
  * Removed rr in favor to rspec mock framework
@@ -67,40 +73,31 @@
67
73
  * [#7] Do not force white color on status
68
74
  * [#8] Yield a block with the filename on directory
69
75
 
70
- == 0.11, released 2009-07-01
71
-
76
+ ## 0.11, released 2009-07-01
72
77
  * Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
73
78
  Thor classes.
74
-
75
79
  * BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
76
80
  since it may cause wrong behavior in the invocation system.
77
-
78
81
  * thor help now show information about any class/task. All those calls are
79
82
  possible:
80
83
 
81
- thor help describe
82
- thor help describe:amazing
83
-
84
+ thor help describe
85
+ thor help describe:amazing
84
86
  Or even with default namespaces:
85
87
 
86
- thor help :spec
87
-
88
+ thor help :spec
88
89
  * Thor::Runner now invokes the default task if none is supplied:
89
90
 
90
- thor describe # invokes the default task, usually help
91
-
91
+ thor describe # invokes the default task, usually help
92
92
  * Thor::Runner now works with mappings:
93
93
 
94
- thor describe -h
95
-
94
+ thor describe -h
96
95
  * Added some documentation and code refactoring.
97
96
 
98
- == 0.9.8, released 2008-10-20
99
-
97
+ ## 0.9.8, released 2008-10-20
100
98
  * Fixed some tiny issues that were introduced lately.
101
99
 
102
- == 0.9.7, released 2008-10-13
103
-
100
+ ## 0.9.7, released 2008-10-13
104
101
  * Setting global method options on the initialize method works as expected:
105
102
  All other tasks will accept these global options in addition to their own.
106
103
  * Added 'group' notion to Thor task sets (class Thor); by default all tasks
@@ -108,12 +105,10 @@
108
105
  tasks - adding --all will show all tasks. You can also filter on a specific
109
106
  group using the --group option: thor -T --group advanced
110
107
 
111
- == 0.9.6, released 2008-09-13
112
-
108
+ ## 0.9.6, released 2008-09-13
113
109
  * Generic improvements
114
110
 
115
- == 0.9.5, released 2008-08-27
116
-
111
+ ## 0.9.5, released 2008-08-27
117
112
  * Improve Windows compatibility
118
113
  * Update (incorrect) README and task.thor sample file
119
114
  * Options hash is now frozen (once returned)
@@ -124,8 +119,7 @@
124
119
  * Don't write options for nil or false values. This allows, for example, turning color off when running specs.
125
120
  * Exit with the status of the spec command to help CI stuff out some.
126
121
 
127
- == 0.9.4, released 2008-08-13
128
-
122
+ ## 0.9.4, released 2008-08-13
129
123
  * Try to add Windows compatibility.
130
124
  * BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
131
125
  * Allow options at the beginning of the argument list as well as the end.
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
+ [![Gem Version](https://badge.fury.io/rb/thor.png)](https://rubygems.org/gems/thor)
1
2
  [![Build Status](https://secure.travis-ci.org/wycats/thor.png?branch=master)](http://travis-ci.org/wycats/thor)
3
+ [![Dependency Status](https://gemnasium.com/wycats/thor.png?travis)](https://gemnasium.com/wycats/thor)
4
+ [![Code Climate](https://codeclimate.com/github/wycats/thor.png)](https://codeclimate.com/github/wycats/thor)
5
+ [![Coverage Status](https://coveralls.io/repos/wycats/thor/badge.png?branch=master)](https://coveralls.io/r/wycats/thor)
2
6
 
3
7
  Thor
4
8
  ====
@@ -19,10 +23,13 @@ Installation
19
23
 
20
24
  Usage and documentation
21
25
  -----------------------
22
- Please see [the wiki](https://github.com/wycats/thor/wiki) for basic usage and other documentation on using Thor.
26
+ Please see the [wiki][] for basic usage and other documentation on using Thor. You can also checkout the [official homepage][homepage].
27
+
28
+ [wiki]: https://github.com/wycats/thor/wiki
29
+ [homepage]: http://whatisthor.com/
23
30
 
24
31
  License
25
32
  -------
26
- Released under the MIT License. See the [LICENSE][license] file for further details.
33
+ Released under the MIT License. See the [LICENSE][] file for further details.
27
34
 
28
- [license]: https://github.com/wycats/thor/blob/master/LICENSE.md
35
+ [license]: LICENSE.md
@@ -3,21 +3,32 @@ require 'thor/base'
3
3
 
4
4
  class Thor
5
5
  class << self
6
- # Sets the default task when thor is executed without an explicit task to be called.
6
+ # Allows for custom "Command" package naming.
7
+ #
8
+ # === Parameters
9
+ # name<String>
10
+ # options<Hash>
11
+ #
12
+ def package_name(name, options={})
13
+ @package_name = name.nil? || name == '' ? nil : name
14
+ end
15
+
16
+ # Sets the default command when thor is executed without an explicit command to be called.
7
17
  #
8
18
  # ==== Parameters
9
- # meth<Symbol>:: name of the default task
19
+ # meth<Symbol>:: name of the default command
10
20
  #
11
- def default_task(meth=nil)
12
- @default_task = case meth
21
+ def default_command(meth=nil)
22
+ @default_command = case meth
13
23
  when :none
14
24
  'help'
15
25
  when nil
16
- @default_task || from_superclass(:default_task, 'help')
26
+ @default_command || from_superclass(:default_command, 'help')
17
27
  else
18
28
  meth.to_s
19
29
  end
20
30
  end
31
+ alias default_task default_command
21
32
 
22
33
  # Registers another Thor subclass as a command.
23
34
  #
@@ -36,7 +47,7 @@ class Thor
36
47
  end
37
48
  end
38
49
 
39
- # Defines the usage and the description of the next task.
50
+ # Defines the usage and the description of the next command.
40
51
  #
41
52
  # ==== Parameters
42
53
  # usage<String>
@@ -45,29 +56,29 @@ class Thor
45
56
  #
46
57
  def desc(usage, description, options={})
47
58
  if options[:for]
48
- task = find_and_refresh_task(options[:for])
49
- task.usage = usage if usage
50
- task.description = description if description
59
+ command = find_and_refresh_command(options[:for])
60
+ command.usage = usage if usage
61
+ command.description = description if description
51
62
  else
52
63
  @usage, @desc, @hide = usage, description, options[:hide] || false
53
64
  end
54
65
  end
55
66
 
56
- # Defines the long description of the next task.
67
+ # Defines the long description of the next command.
57
68
  #
58
69
  # ==== Parameters
59
70
  # long description<String>
60
71
  #
61
72
  def long_desc(long_description, options={})
62
73
  if options[:for]
63
- task = find_and_refresh_task(options[:for])
64
- task.long_description = long_description if long_description
74
+ command = find_and_refresh_command(options[:for])
75
+ command.long_description = long_description if long_description
65
76
  else
66
77
  @long_desc = long_description
67
78
  end
68
79
  end
69
80
 
70
- # Maps an input to a task. If you define:
81
+ # Maps an input to a command. If you define:
71
82
  #
72
83
  # map "-T" => "list"
73
84
  #
@@ -75,10 +86,10 @@ class Thor
75
86
  #
76
87
  # thor -T
77
88
  #
78
- # Will invoke the list task.
89
+ # Will invoke the list command.
79
90
  #
80
91
  # ==== Parameters
81
- # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task.
92
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
82
93
  #
83
94
  def map(mappings=nil)
84
95
  @map ||= from_superclass(:map, {})
@@ -96,7 +107,7 @@ class Thor
96
107
  @map
97
108
  end
98
109
 
99
- # Declares the options for the next task to be declared.
110
+ # Declares the options for the next command to be declared.
100
111
  #
101
112
  # ==== Parameters
102
113
  # Hash[Symbol => Object]:: The hash key is the name of the option and the value
@@ -112,15 +123,15 @@ class Thor
112
123
  alias options method_options
113
124
 
114
125
  # Adds an option to the set of method options. If :for is given as option,
115
- # it allows you to change the options from a previous defined task.
126
+ # it allows you to change the options from a previous defined command.
116
127
  #
117
- # def previous_task
128
+ # def previous_command
118
129
  # # magic
119
130
  # end
120
131
  #
121
- # method_option :foo => :bar, :for => :previous_task
132
+ # method_option :foo => :bar, :for => :previous_command
122
133
  #
123
- # def next_task
134
+ # def next_command
124
135
  # # magic
125
136
  # end
126
137
  #
@@ -139,38 +150,38 @@ class Thor
139
150
  #
140
151
  def method_option(name, options={})
141
152
  scope = if options[:for]
142
- find_and_refresh_task(options[:for]).options
153
+ find_and_refresh_command(options[:for]).options
143
154
  else
144
155
  method_options
145
156
  end
146
157
 
147
158
  build_option(name, options, scope)
148
159
  end
149
-
150
160
  alias option method_option
151
161
 
152
- # Prints help information for the given task.
162
+ # Prints help information for the given command.
153
163
  #
154
164
  # ==== Parameters
155
165
  # shell<Thor::Shell>
156
- # task_name<String>
166
+ # command_name<String>
157
167
  #
158
- def task_help(shell, task_name)
159
- meth = normalize_task_name(task_name)
160
- task = all_tasks[meth]
161
- handle_no_task_error(meth) unless task
168
+ def command_help(shell, command_name)
169
+ meth = normalize_command_name(command_name)
170
+ command = all_commands[meth]
171
+ handle_no_command_error(meth) unless command
162
172
 
163
173
  shell.say "Usage:"
164
- shell.say " #{banner(task)}"
174
+ shell.say " #{banner(command)}"
165
175
  shell.say
166
- class_options_help(shell, nil => task.options.map { |_, o| o })
167
- if task.long_description
176
+ class_options_help(shell, nil => command.options.map { |_, o| o })
177
+ if command.long_description
168
178
  shell.say "Description:"
169
- shell.print_wrapped(task.long_description, :indent => 2)
179
+ shell.print_wrapped(command.long_description, :indent => 2)
170
180
  else
171
- shell.say task.description
181
+ shell.say command.description
172
182
  end
173
183
  end
184
+ alias task_help command_help
174
185
 
175
186
  # Prints help information for this class.
176
187
  #
@@ -178,32 +189,39 @@ class Thor
178
189
  # shell<Thor::Shell>
179
190
  #
180
191
  def help(shell, subcommand = false)
181
- list = printable_tasks(true, subcommand)
192
+ list = printable_commands(true, subcommand)
182
193
  Thor::Util.thor_classes_in(self).each do |klass|
183
- list += klass.printable_tasks(false)
194
+ list += klass.printable_commands(false)
184
195
  end
185
196
  list.sort!{ |a,b| a[0] <=> b[0] }
186
197
 
187
- shell.say "Tasks:"
198
+ if @package_name
199
+ shell.say "#{@package_name} commands:"
200
+ else
201
+ shell.say "Commands:"
202
+ end
203
+
188
204
  shell.print_table(list, :indent => 2, :truncate => true)
189
205
  shell.say
190
206
  class_options_help(shell)
191
207
  end
192
208
 
193
- # Returns tasks ready to be printed.
194
- def printable_tasks(all = true, subcommand = false)
195
- (all ? all_tasks : tasks).map do |_, task|
196
- next if task.hidden?
209
+ # Returns commands ready to be printed.
210
+ def printable_commands(all = true, subcommand = false)
211
+ (all ? all_commands : commands).map do |_, command|
212
+ next if command.hidden?
197
213
  item = []
198
- item << banner(task, false, subcommand)
199
- item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
214
+ item << banner(command, false, subcommand)
215
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
200
216
  item
201
217
  end.compact
202
218
  end
219
+ alias printable_tasks printable_commands
203
220
 
204
221
  def subcommands
205
222
  @subcommands ||= from_superclass(:subcommands, [])
206
223
  end
224
+ alias subtasks subcommands
207
225
 
208
226
  def subcommand(subcommand, subcommand_class)
209
227
  self.subcommands << subcommand.to_s
@@ -211,9 +229,10 @@ class Thor
211
229
 
212
230
  define_method(subcommand) do |*args|
213
231
  args, opts = Thor::Arguments.split(args)
214
- invoke subcommand_class, args, opts, :invoked_via_subcommand => true
232
+ invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
215
233
  end
216
234
  end
235
+ alias subtask subcommand
217
236
 
218
237
  # Extend check unknown options to accept a hash of conditions.
219
238
  #
@@ -236,10 +255,10 @@ class Thor
236
255
  options = check_unknown_options
237
256
  return false unless options
238
257
 
239
- task = config[:current_task]
240
- return true unless task
258
+ command = config[:current_command]
259
+ return true unless command
241
260
 
242
- name = task.name
261
+ name = command.name
243
262
 
244
263
  if subcommands.include?(name)
245
264
  false
@@ -253,16 +272,16 @@ class Thor
253
272
  end
254
273
 
255
274
  # Stop parsing of options as soon as an unknown option or a regular
256
- # argument is encountered. All remaining arguments are passed to the task.
257
- # This is useful if you have a task that can receive arbitrary additional
275
+ # argument is encountered. All remaining arguments are passed to the command.
276
+ # This is useful if you have a command that can receive arbitrary additional
258
277
  # options, and where those additional options should not be handled by
259
278
  # Thor.
260
279
  #
261
280
  # ==== Example
262
281
  #
263
- # To better understand how this is useful, let's consider a task that calls
282
+ # To better understand how this is useful, let's consider a command that calls
264
283
  # an external command. A user may want to pass arbitrary options and
265
- # arguments to that command. The task itself also accepts some options,
284
+ # arguments to that command. The command itself also accepts some options,
266
285
  # which should be handled by Thor.
267
286
  #
268
287
  # class_option "verbose", :type => :boolean
@@ -288,161 +307,167 @@ class Thor
288
307
  # --verbose foo
289
308
  #
290
309
  # ==== Parameters
291
- # Symbol ...:: A list of tasks that should be affected.
292
- def stop_on_unknown_option!(*task_names)
310
+ # Symbol ...:: A list of commands that should be affected.
311
+ def stop_on_unknown_option!(*command_names)
293
312
  @stop_on_unknown_option ||= Set.new
294
- @stop_on_unknown_option.merge(task_names)
313
+ @stop_on_unknown_option.merge(command_names)
295
314
  end
296
315
 
297
- def stop_on_unknown_option?(task) #:nodoc:
298
- !!@stop_on_unknown_option && @stop_on_unknown_option.include?(task.name.to_sym)
316
+ def stop_on_unknown_option?(command) #:nodoc:
317
+ !!@stop_on_unknown_option && @stop_on_unknown_option.include?(command.name.to_sym)
299
318
  end
300
319
 
301
- protected
302
-
303
- # The method responsible for dispatching given the args.
304
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
305
- # There is an edge case when dispatching from a subcommand.
306
- # A problem occurs invoking the default task. This case occurs
307
- # when arguments are passed and a default task is defined, and
308
- # the first given_args does not match the default task.
309
- # Thor use "help" by default so we skip that case.
310
- # Note the call to retrieve_task_name. It's called with
311
- # given_args.dup since that method calls args.shift. Then lookup
312
- # the task normally. If the first item in given_args is not
313
- # a task then use the default task. The given_args will be
314
- # intact later since dup was used.
315
- if config[:invoked_via_subcommand] && given_args.size >= 1 && default_task != "help" && given_args.first != default_task
316
- meth ||= retrieve_task_name(given_args.dup)
317
- task = all_tasks[normalize_task_name(meth)]
318
- task ||= all_tasks[normalize_task_name(default_task)]
319
- else
320
- meth ||= retrieve_task_name(given_args)
321
- task = all_tasks[normalize_task_name(meth)]
322
- end
320
+ protected
321
+
322
+ # The method responsible for dispatching given the args.
323
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
324
+ # There is an edge case when dispatching from a subcommand.
325
+ # A problem occurs invoking the default command. This case occurs
326
+ # when arguments are passed and a default command is defined, and
327
+ # the first given_args does not match the default command.
328
+ # Thor use "help" by default so we skip that case.
329
+ # Note the call to retrieve_command_name. It's called with
330
+ # given_args.dup since that method calls args.shift. Then lookup
331
+ # the command normally. If the first item in given_args is not
332
+ # a command then use the default command. The given_args will be
333
+ # intact later since dup was used.
334
+ if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != "help" && given_args.first != default_command
335
+ meth ||= retrieve_command_name(given_args.dup)
336
+ command = all_commands[normalize_command_name(meth)]
337
+ command ||= all_commands[normalize_command_name(default_command)]
338
+ else
339
+ meth ||= retrieve_command_name(given_args)
340
+ command = all_commands[normalize_command_name(meth)]
341
+ end
323
342
 
324
- if task
325
- args, opts = Thor::Options.split(given_args)
326
- if stop_on_unknown_option?(task) && !args.empty?
327
- # given_args starts with a non-option, so we treat everything as
328
- # ordinary arguments
329
- args.concat opts
330
- opts.clear
331
- end
332
- else
333
- args, opts = given_args, nil
334
- task = Thor::DynamicTask.new(meth)
343
+ if command
344
+ args, opts = Thor::Options.split(given_args)
345
+ if stop_on_unknown_option?(command) && !args.empty?
346
+ # given_args starts with a non-option, so we treat everything as
347
+ # ordinary arguments
348
+ args.concat opts
349
+ opts.clear
335
350
  end
336
-
337
- opts = given_opts || opts || []
338
- config.merge!(:current_task => task, :task_options => task.options)
339
-
340
- instance = new(args, opts, config)
341
- yield instance if block_given?
342
- args = instance.args
343
- trailing = args[Range.new(arguments.size, -1)]
344
- instance.invoke_task(task, trailing || [])
351
+ else
352
+ args, opts = given_args, nil
353
+ command = Thor::DynamicCommand.new(meth)
345
354
  end
346
355
 
347
- # The banner for this class. You can customize it if you are invoking the
348
- # thor class by another ways which is not the Thor::Runner. It receives
349
- # the task that is going to be invoked and a boolean which indicates if
350
- # the namespace should be displayed as arguments.
351
- #
352
- def banner(task, namespace = nil, subcommand = false)
353
- "#{basename} #{task.formatted_usage(self, $thor_runner, subcommand)}"
354
- end
356
+ opts = given_opts || opts || []
357
+ config.merge!(:current_command => command, :command_options => command.options)
355
358
 
356
- def baseclass #:nodoc:
357
- Thor
358
- end
359
+ instance = new(args, opts, config)
360
+ yield instance if block_given?
361
+ args = instance.args
362
+ trailing = args[Range.new(arguments.size, -1)]
363
+ instance.invoke_command(command, trailing || [])
364
+ end
359
365
 
360
- def create_task(meth) #:nodoc:
361
- if @usage && @desc
362
- base_class = @hide ? Thor::HiddenTask : Thor::Task
363
- tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
364
- @usage, @desc, @long_desc, @method_options, @hide = nil
365
- true
366
- elsif self.all_tasks[meth] || meth == "method_missing"
367
- true
368
- else
369
- puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
370
- "Call desc if you want this method to be available as task or declare it inside a " <<
371
- "no_tasks{} block. Invoked from #{caller[1].inspect}."
372
- false
373
- end
374
- end
366
+ # The banner for this class. You can customize it if you are invoking the
367
+ # thor class by another ways which is not the Thor::Runner. It receives
368
+ # the command that is going to be invoked and a boolean which indicates if
369
+ # the namespace should be displayed as arguments.
370
+ #
371
+ def banner(command, namespace = nil, subcommand = false)
372
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
373
+ end
375
374
 
376
- def initialize_added #:nodoc:
377
- class_options.merge!(method_options)
378
- @method_options = nil
379
- end
375
+ def baseclass #:nodoc:
376
+ Thor
377
+ end
380
378
 
381
- # Retrieve the task name from given args.
382
- def retrieve_task_name(args) #:nodoc:
383
- meth = args.first.to_s unless args.empty?
384
- if meth && (map[meth] || meth !~ /^\-/)
385
- args.shift
386
- else
387
- nil
388
- end
379
+ def create_command(meth) #:nodoc:
380
+ if @usage && @desc
381
+ base_class = @hide ? Thor::HiddenCommand : Thor::Command
382
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
383
+ @usage, @desc, @long_desc, @method_options, @hide = nil
384
+ true
385
+ elsif self.all_commands[meth] || meth == "method_missing"
386
+ true
387
+ else
388
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
389
+ "Call desc if you want this method to be available as command or declare it inside a " <<
390
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
391
+ false
389
392
  end
393
+ end
394
+ alias create_task create_command
390
395
 
391
- # receives a (possibly nil) task name and returns a name that is in
392
- # the tasks hash. In addition to normalizing aliases, this logic
393
- # will determine if a shortened command is an unambiguous substring of
394
- # a task or alias.
395
- #
396
- # +normalize_task_name+ also converts names like +animal-prison+
397
- # into +animal_prison+.
398
- def normalize_task_name(meth) #:nodoc:
399
- return default_task.to_s.gsub('-', '_') unless meth
400
-
401
- possibilities = find_task_possibilities(meth)
402
- if possibilities.size > 1
403
- raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]"
404
- elsif possibilities.size < 1
405
- meth = meth || default_task
406
- elsif map[meth]
407
- meth = map[meth]
408
- else
409
- meth = possibilities.first
410
- end
396
+ def initialize_added #:nodoc:
397
+ class_options.merge!(method_options)
398
+ @method_options = nil
399
+ end
411
400
 
412
- meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
401
+ # Retrieve the command name from given args.
402
+ def retrieve_command_name(args) #:nodoc:
403
+ meth = args.first.to_s unless args.empty?
404
+ if meth && (map[meth] || meth !~ /^\-/)
405
+ args.shift
406
+ else
407
+ nil
413
408
  end
414
-
415
- # this is the logic that takes the task name passed in by the user
416
- # and determines whether it is an unambiguous substrings of a task or
417
- # alias name.
418
- def find_task_possibilities(meth)
419
- len = meth.to_s.length
420
- possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort
421
- unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
422
-
423
- if possibilities.include?(meth)
424
- [meth]
425
- elsif unique_possibilities.size == 1
426
- unique_possibilities
427
- else
428
- possibilities
429
- end
409
+ end
410
+ alias retrieve_task_name retrieve_command_name
411
+
412
+ # receives a (possibly nil) command name and returns a name that is in
413
+ # the commands hash. In addition to normalizing aliases, this logic
414
+ # will determine if a shortened command is an unambiguous substring of
415
+ # a command or alias.
416
+ #
417
+ # +normalize_command_name+ also converts names like +animal-prison+
418
+ # into +animal_prison+.
419
+ def normalize_command_name(meth) #:nodoc:
420
+ return default_command.to_s.gsub('-', '_') unless meth
421
+
422
+ possibilities = find_command_possibilities(meth)
423
+ if possibilities.size > 1
424
+ raise ArgumentError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
425
+ elsif possibilities.size < 1
426
+ meth = meth || default_command
427
+ elsif map[meth]
428
+ meth = map[meth]
429
+ else
430
+ meth = possibilities.first
430
431
  end
431
432
 
432
- def subcommand_help(cmd)
433
- desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
434
- class_eval <<-RUBY
435
- def help(task = nil, subcommand = true); super; end
436
- RUBY
433
+ meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
434
+ end
435
+ alias normalize_task_name normalize_command_name
436
+
437
+ # this is the logic that takes the command name passed in by the user
438
+ # and determines whether it is an unambiguous substrings of a command or
439
+ # alias name.
440
+ def find_command_possibilities(meth)
441
+ len = meth.to_s.length
442
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
443
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
444
+
445
+ if possibilities.include?(meth)
446
+ [meth]
447
+ elsif unique_possibilities.size == 1
448
+ unique_possibilities
449
+ else
450
+ possibilities
437
451
  end
452
+ end
453
+ alias find_task_possibilities find_command_possibilities
454
+
455
+ def subcommand_help(cmd)
456
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
457
+ class_eval <<-RUBY
458
+ def help(command = nil, subcommand = true); super; end
459
+ RUBY
460
+ end
461
+ alias subtask_help subcommand_help
462
+
438
463
  end
439
464
 
440
465
  include Thor::Base
441
466
 
442
467
  map HELP_MAPPINGS => :help
443
468
 
444
- desc "help [TASK]", "Describe available tasks or one specific task"
445
- def help(task = nil, subcommand = false)
446
- task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
469
+ desc "help [COMMAND]", "Describe available commands or one specific command"
470
+ def help(command = nil, subcommand = false)
471
+ command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
447
472
  end
448
473
  end