engineyard 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  module EY
2
- VERSION = '2.1.1'
3
- ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '2.1.1'
2
+ VERSION = '2.1.2'
3
+ ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '2.1.3'
4
4
  end
@@ -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
@@ -1,22 +1,34 @@
1
+ require 'set'
1
2
  require 'thor/base'
2
3
 
3
4
  class Thor
4
5
  class << self
5
- # 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.
6
17
  #
7
18
  # ==== Parameters
8
- # meth<Symbol>:: name of the default task
9
- #
10
- def default_task(meth=nil)
11
- case meth
12
- when :none
13
- @default_task = 'help'
14
- when nil
15
- @default_task ||= from_superclass(:default_task, 'help')
16
- else
17
- @default_task = meth.to_s
19
+ # meth<Symbol>:: name of the default command
20
+ #
21
+ def default_command(meth=nil)
22
+ @default_command = case meth
23
+ when :none
24
+ 'help'
25
+ when nil
26
+ @default_command || from_superclass(:default_command, 'help')
27
+ else
28
+ meth.to_s
18
29
  end
19
30
  end
31
+ alias default_task default_command
20
32
 
21
33
  # Registers another Thor subclass as a command.
22
34
  #
@@ -35,7 +47,7 @@ class Thor
35
47
  end
36
48
  end
37
49
 
38
- # Defines the usage and the description of the next task.
50
+ # Defines the usage and the description of the next command.
39
51
  #
40
52
  # ==== Parameters
41
53
  # usage<String>
@@ -44,29 +56,29 @@ class Thor
44
56
  #
45
57
  def desc(usage, description, options={})
46
58
  if options[:for]
47
- task = find_and_refresh_task(options[:for])
48
- task.usage = usage if usage
49
- 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
50
62
  else
51
63
  @usage, @desc, @hide = usage, description, options[:hide] || false
52
64
  end
53
65
  end
54
66
 
55
- # Defines the long description of the next task.
67
+ # Defines the long description of the next command.
56
68
  #
57
69
  # ==== Parameters
58
70
  # long description<String>
59
71
  #
60
72
  def long_desc(long_description, options={})
61
73
  if options[:for]
62
- task = find_and_refresh_task(options[:for])
63
- 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
64
76
  else
65
77
  @long_desc = long_description
66
78
  end
67
79
  end
68
80
 
69
- # Maps an input to a task. If you define:
81
+ # Maps an input to a command. If you define:
70
82
  #
71
83
  # map "-T" => "list"
72
84
  #
@@ -74,10 +86,10 @@ class Thor
74
86
  #
75
87
  # thor -T
76
88
  #
77
- # Will invoke the list task.
89
+ # Will invoke the list command.
78
90
  #
79
91
  # ==== Parameters
80
- # 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.
81
93
  #
82
94
  def map(mappings=nil)
83
95
  @map ||= from_superclass(:map, {})
@@ -95,7 +107,7 @@ class Thor
95
107
  @map
96
108
  end
97
109
 
98
- # Declares the options for the next task to be declared.
110
+ # Declares the options for the next command to be declared.
99
111
  #
100
112
  # ==== Parameters
101
113
  # Hash[Symbol => Object]:: The hash key is the name of the option and the value
@@ -111,15 +123,15 @@ class Thor
111
123
  alias options method_options
112
124
 
113
125
  # Adds an option to the set of method options. If :for is given as option,
114
- # 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.
115
127
  #
116
- # def previous_task
128
+ # def previous_command
117
129
  # # magic
118
130
  # end
119
131
  #
120
- # method_option :foo => :bar, :for => :previous_task
132
+ # method_option :foo => :bar, :for => :previous_command
121
133
  #
122
- # def next_task
134
+ # def next_command
123
135
  # # magic
124
136
  # end
125
137
  #
@@ -138,38 +150,38 @@ class Thor
138
150
  #
139
151
  def method_option(name, options={})
140
152
  scope = if options[:for]
141
- find_and_refresh_task(options[:for]).options
153
+ find_and_refresh_command(options[:for]).options
142
154
  else
143
155
  method_options
144
156
  end
145
157
 
146
158
  build_option(name, options, scope)
147
159
  end
148
-
149
160
  alias option method_option
150
161
 
151
- # Prints help information for the given task.
162
+ # Prints help information for the given command.
152
163
  #
153
164
  # ==== Parameters
154
165
  # shell<Thor::Shell>
155
- # task_name<String>
166
+ # command_name<String>
156
167
  #
157
- def task_help(shell, task_name)
158
- meth = normalize_task_name(task_name)
159
- task = all_tasks[meth]
160
- 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
161
172
 
162
173
  shell.say "Usage:"
163
- shell.say " #{banner(task)}"
174
+ shell.say " #{banner(command)}"
164
175
  shell.say
165
- class_options_help(shell, nil => task.options.map { |_, o| o })
166
- if task.long_description
176
+ class_options_help(shell, nil => command.options.map { |_, o| o })
177
+ if command.long_description
167
178
  shell.say "Description:"
168
- shell.print_wrapped(task.long_description, :indent => 2)
179
+ shell.print_wrapped(command.long_description, :indent => 2)
169
180
  else
170
- shell.say task.description
181
+ shell.say command.description
171
182
  end
172
183
  end
184
+ alias task_help command_help
173
185
 
174
186
  # Prints help information for this class.
175
187
  #
@@ -177,32 +189,39 @@ class Thor
177
189
  # shell<Thor::Shell>
178
190
  #
179
191
  def help(shell, subcommand = false)
180
- list = printable_tasks(true, subcommand)
192
+ list = printable_commands(true, subcommand)
181
193
  Thor::Util.thor_classes_in(self).each do |klass|
182
- list += klass.printable_tasks(false)
194
+ list += klass.printable_commands(false)
183
195
  end
184
196
  list.sort!{ |a,b| a[0] <=> b[0] }
185
197
 
186
- shell.say "Tasks:"
198
+ if @package_name
199
+ shell.say "#{@package_name} commands:"
200
+ else
201
+ shell.say "Commands:"
202
+ end
203
+
187
204
  shell.print_table(list, :indent => 2, :truncate => true)
188
205
  shell.say
189
206
  class_options_help(shell)
190
207
  end
191
208
 
192
- # Returns tasks ready to be printed.
193
- def printable_tasks(all = true, subcommand = false)
194
- (all ? all_tasks : tasks).map do |_, task|
195
- 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?
196
213
  item = []
197
- item << banner(task, false, subcommand)
198
- item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
214
+ item << banner(command, false, subcommand)
215
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
199
216
  item
200
217
  end.compact
201
218
  end
219
+ alias printable_tasks printable_commands
202
220
 
203
221
  def subcommands
204
222
  @subcommands ||= from_superclass(:subcommands, [])
205
223
  end
224
+ alias subtasks subcommands
206
225
 
207
226
  def subcommand(subcommand, subcommand_class)
208
227
  self.subcommands << subcommand.to_s
@@ -210,9 +229,10 @@ class Thor
210
229
 
211
230
  define_method(subcommand) do |*args|
212
231
  args, opts = Thor::Arguments.split(args)
213
- invoke subcommand_class, args, opts
232
+ invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
214
233
  end
215
234
  end
235
+ alias subtask subcommand
216
236
 
217
237
  # Extend check unknown options to accept a hash of conditions.
218
238
  #
@@ -235,10 +255,10 @@ class Thor
235
255
  options = check_unknown_options
236
256
  return false unless options
237
257
 
238
- task = config[:current_task]
239
- return true unless task
258
+ command = config[:current_command]
259
+ return true unless command
240
260
 
241
- name = task.name
261
+ name = command.name
242
262
 
243
263
  if subcommands.include?(name)
244
264
  false
@@ -251,129 +271,203 @@ class Thor
251
271
  end
252
272
  end
253
273
 
254
- protected
255
-
256
- # The method responsible for dispatching given the args.
257
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
258
- meth ||= retrieve_task_name(given_args)
259
- task = all_tasks[normalize_task_name(meth)]
260
-
261
- if task
262
- args, opts = Thor::Options.split(given_args)
263
- else
264
- args, opts = given_args, nil
265
- task = Thor::DynamicTask.new(meth)
266
- end
274
+ # Stop parsing of options as soon as an unknown option or a regular
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
277
+ # options, and where those additional options should not be handled by
278
+ # Thor.
279
+ #
280
+ # ==== Example
281
+ #
282
+ # To better understand how this is useful, let's consider a command that calls
283
+ # an external command. A user may want to pass arbitrary options and
284
+ # arguments to that command. The command itself also accepts some options,
285
+ # which should be handled by Thor.
286
+ #
287
+ # class_option "verbose", :type => :boolean
288
+ # stop_on_unknown_option! :exec
289
+ # check_unknown_options! :except => :exec
290
+ #
291
+ # desc "exec", "Run a shell command"
292
+ # def exec(*args)
293
+ # puts "diagnostic output" if options[:verbose]
294
+ # Kernel.exec(*args)
295
+ # end
296
+ #
297
+ # Here +exec+ can be called with +--verbose+ to get diagnostic output,
298
+ # e.g.:
299
+ #
300
+ # $ thor exec --verbose echo foo
301
+ # diagnostic output
302
+ # foo
303
+ #
304
+ # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
305
+ #
306
+ # $ thor exec echo --verbose foo
307
+ # --verbose foo
308
+ #
309
+ # ==== Parameters
310
+ # Symbol ...:: A list of commands that should be affected.
311
+ def stop_on_unknown_option!(*command_names)
312
+ @stop_on_unknown_option ||= Set.new
313
+ @stop_on_unknown_option.merge(command_names)
314
+ end
267
315
 
268
- opts = given_opts || opts || []
269
- config.merge!(:current_task => task, :task_options => task.options)
316
+ def stop_on_unknown_option?(command) #:nodoc:
317
+ !!@stop_on_unknown_option && @stop_on_unknown_option.include?(command.name.to_sym)
318
+ end
270
319
 
271
- instance = new(args, opts, config)
272
- yield instance if block_given?
273
- args = instance.args
274
- trailing = args[Range.new(arguments.size, -1)]
275
- instance.invoke_task(task, trailing || [])
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)]
276
341
  end
277
342
 
278
- # The banner for this class. You can customize it if you are invoking the
279
- # thor class by another ways which is not the Thor::Runner. It receives
280
- # the task that is going to be invoked and a boolean which indicates if
281
- # the namespace should be displayed as arguments.
282
- #
283
- def banner(task, namespace = nil, subcommand = false)
284
- "#{basename} #{task.formatted_usage(self, $thor_runner, subcommand)}"
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
350
+ end
351
+ else
352
+ args, opts = given_args, nil
353
+ command = Thor::DynamicCommand.new(meth)
285
354
  end
286
355
 
287
- def baseclass #:nodoc:
288
- Thor
289
- end
356
+ opts = given_opts || opts || []
357
+ config.merge!(:current_command => command, :command_options => command.options)
290
358
 
291
- def create_task(meth) #:nodoc:
292
- if @usage && @desc
293
- base_class = @hide ? Thor::HiddenTask : Thor::Task
294
- tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
295
- @usage, @desc, @long_desc, @method_options, @hide = nil
296
- true
297
- elsif self.all_tasks[meth] || meth == "method_missing"
298
- true
299
- else
300
- puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
301
- "Call desc if you want this method to be available as task or declare it inside a " <<
302
- "no_tasks{} block. Invoked from #{caller[1].inspect}."
303
- false
304
- end
305
- 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
306
365
 
307
- def initialize_added #:nodoc:
308
- class_options.merge!(method_options)
309
- @method_options = nil
310
- 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
311
374
 
312
- # Retrieve the task name from given args.
313
- def retrieve_task_name(args) #:nodoc:
314
- meth = args.first.to_s unless args.empty?
315
- if meth && (map[meth] || meth !~ /^\-/)
316
- args.shift
317
- else
318
- nil
319
- end
375
+ def baseclass #:nodoc:
376
+ Thor
377
+ end
378
+
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
320
392
  end
393
+ end
394
+ alias create_task create_command
321
395
 
322
- # receives a (possibly nil) task name and returns a name that is in
323
- # the tasks hash. In addition to normalizing aliases, this logic
324
- # will determine if a shortened command is an unambiguous substring of
325
- # a task or alias.
326
- #
327
- # +normalize_task_name+ also converts names like +animal-prison+
328
- # into +animal_prison+.
329
- def normalize_task_name(meth) #:nodoc:
330
- return default_task.to_s.gsub('-', '_') unless meth
331
-
332
- possibilities = find_task_possibilities(meth)
333
- if possibilities.size > 1
334
- raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]"
335
- elsif possibilities.size < 1
336
- meth = meth || default_task
337
- elsif map[meth]
338
- meth = map[meth]
339
- else
340
- meth = possibilities.first
341
- end
396
+ def initialize_added #:nodoc:
397
+ class_options.merge!(method_options)
398
+ @method_options = nil
399
+ end
342
400
 
343
- 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
344
408
  end
409
+ end
410
+ alias retrieve_task_name retrieve_command_name
345
411
 
346
- # this is the logic that takes the task name passed in by the user
347
- # and determines whether it is an unambiguous substrings of a task or
348
- # alias name.
349
- def find_task_possibilities(meth)
350
- len = meth.to_s.length
351
- possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort
352
- unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
353
-
354
- if possibilities.include?(meth)
355
- [meth]
356
- elsif unique_possibilities.size == 1
357
- unique_possibilities
358
- else
359
- possibilities
360
- end
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
361
431
  end
362
432
 
363
- def subcommand_help(cmd)
364
- desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
365
- class_eval <<-RUBY
366
- def help(task = nil, subcommand = true); super; end
367
- 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
368
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
+
369
463
  end
370
464
 
371
465
  include Thor::Base
372
466
 
373
467
  map HELP_MAPPINGS => :help
374
468
 
375
- desc "help [TASK]", "Describe available tasks or one specific task"
376
- def help(task = nil, subcommand = false)
377
- 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)
378
472
  end
379
473
  end