thor 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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