bundler 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (58) hide show
  1. data/CHANGELOG.md +26 -2
  2. data/bin/bundle +1 -3
  3. data/bundler.gemspec +1 -1
  4. data/lib/bundler/cli.rb +2 -4
  5. data/lib/bundler/fetcher.rb +13 -12
  6. data/lib/bundler/installer.rb +9 -36
  7. data/lib/bundler/parallel_workers/unix_worker.rb +12 -4
  8. data/lib/bundler/parallel_workers/worker.rb +1 -0
  9. data/lib/bundler/rubygems_ext.rb +1 -1
  10. data/lib/bundler/rubygems_integration.rb +15 -8
  11. data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  12. data/lib/bundler/vendor/thor.rb +63 -56
  13. data/lib/bundler/vendor/thor/actions.rb +52 -51
  14. data/lib/bundler/vendor/thor/actions/create_file.rb +35 -37
  15. data/lib/bundler/vendor/thor/actions/create_link.rb +1 -2
  16. data/lib/bundler/vendor/thor/actions/directory.rb +36 -37
  17. data/lib/bundler/vendor/thor/actions/empty_directory.rb +67 -69
  18. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +11 -12
  19. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +41 -43
  20. data/lib/bundler/vendor/thor/base.rb +180 -178
  21. data/lib/bundler/vendor/thor/command.rb +22 -25
  22. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +21 -24
  23. data/lib/bundler/vendor/thor/core_ext/io_binary_read.rb +1 -3
  24. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +8 -10
  25. data/lib/bundler/vendor/thor/error.rb +2 -2
  26. data/lib/bundler/vendor/thor/group.rb +59 -60
  27. data/lib/bundler/vendor/thor/invocation.rb +39 -38
  28. data/lib/bundler/vendor/thor/line_editor.rb +17 -0
  29. data/lib/bundler/vendor/thor/line_editor/basic.rb +35 -0
  30. data/lib/bundler/vendor/thor/line_editor/readline.rb +88 -0
  31. data/lib/bundler/vendor/thor/parser/argument.rb +29 -30
  32. data/lib/bundler/vendor/thor/parser/arguments.rb +102 -98
  33. data/lib/bundler/vendor/thor/parser/option.rb +25 -25
  34. data/lib/bundler/vendor/thor/parser/options.rb +85 -85
  35. data/lib/bundler/vendor/thor/rake_compat.rb +6 -7
  36. data/lib/bundler/vendor/thor/runner.rb +154 -154
  37. data/lib/bundler/vendor/thor/shell.rb +23 -30
  38. data/lib/bundler/vendor/thor/shell/basic.rb +66 -57
  39. data/lib/bundler/vendor/thor/shell/color.rb +44 -43
  40. data/lib/bundler/vendor/thor/shell/html.rb +43 -44
  41. data/lib/bundler/vendor/thor/util.rb +37 -40
  42. data/lib/bundler/vendor/thor/version.rb +1 -1
  43. data/lib/bundler/version.rb +1 -1
  44. data/man/bundle-install.ronn +1 -1
  45. data/man/gemfile.5.ronn +1 -2
  46. data/spec/commands/binstubs_spec.rb +13 -0
  47. data/spec/install/gemfile/git_spec.rb +2 -2
  48. data/spec/install/gems/dependency_api_spec.rb +34 -0
  49. data/spec/install/gems/packed_spec.rb +2 -4
  50. data/spec/quality_spec.rb +2 -2
  51. data/spec/realworld/parallel_spec.rb +69 -0
  52. data/spec/runtime/setup_spec.rb +3 -2
  53. data/spec/spec_helper.rb +1 -0
  54. data/spec/support/artifice/endpoint_host_redirect.rb +15 -0
  55. data/spec/support/permissions.rb +11 -0
  56. metadata +11 -6
  57. data/spec/realworld/parallel_install_spec.rb +0 -23
  58. data/spec/realworld/parallel_update_spec.rb +0 -31
@@ -1,3 +1,14 @@
1
+ ## 1.5.2 (2014-01-10)
2
+
3
+ Bugfixes:
4
+
5
+ - fix integration with Rubygems 1.8.0-1.8.19
6
+ - handle ENETDOWN exception during network requests
7
+ - gracefully shut down after interrupt during parallel install (@Who828)
8
+ - allow Rails to run Thor without debug mode (@rafaelfranca)
9
+ - set git binstub permissions by umask (@v-yarotsky)
10
+ - remove parallel install debug log
11
+
1
12
  ## 1.5.1 (2013-12-28)
2
13
 
3
14
  Bugfixes:
@@ -96,12 +107,25 @@ Bugfixes:
96
107
  - allow the same options hash to be passed to multiple gems (#2447)
97
108
  - handle missing binaries without an exception (#2019, @luismreis)
98
109
 
99
- ## 1.3.6
110
+ ## 1.3.6 (8 January 2014)
100
111
 
101
112
  Bugfixes:
102
113
 
103
- - set --no-cache when bundle install --local is called (@TimMoore)
104
114
  - make gemspec path option preserve relative paths in lock file (@bwillis)
115
+ - use umask when creating binstubs (#1618, @v-yarotsky)
116
+ - warn if graphviz is not installed (#2435, @Agis-)
117
+ - show git errors while loading gemspecs
118
+ - don't mutate gem method options hash (#2447)
119
+ - print Thor errors (#2478, @pjvds)
120
+ - print Rubygems system exit errors (James Cook)
121
+ - more Pathnames into Strings for MacRuby (@kml)
122
+ - preserve original gemspec path (@bwillis)
123
+ - remove warning about deps with :git (#1651, @ixti)
124
+ - split git files on null (#2634, @jasonmp85)
125
+ - handle cross-host redirects without SSL (#2686, @grddev)
126
+ - handle Rubygems 2 security exception (@zzak)
127
+ - reinstall gems if they are missing with spec present
128
+ - set binstub permissions using umask (#1618, @v-yarotsky)
105
129
 
106
130
  ## 1.3.5 (3 April 2013)
107
131
 
data/bin/bundle CHANGED
@@ -15,8 +15,6 @@ $LOAD_PATH.each do |path|
15
15
  end
16
16
 
17
17
  require 'bundler/cli'
18
- # Force Thor to raise exceptions so we can exit non-zero.
19
- ENV["THOR_DEBUG"] = "1"
20
18
 
21
19
  require 'bundler/friendly_errors'
22
- Bundler.with_friendly_errors { Bundler::CLI.start }
20
+ Bundler.with_friendly_errors { Bundler::CLI.start(ARGV, :debug => true) }
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.add_development_dependency 'ronn', '~> 0.7.3'
20
20
  spec.add_development_dependency 'rspec', '~> 2.11'
21
21
 
22
- spec.files = `git ls-files`.split($/)
22
+ spec.files = `git ls-files -z`.split("\x0")
23
23
  spec.files += Dir.glob('lib/bundler/man/**/*') # man/ is ignored by git
24
24
  spec.test_files = spec.files.grep(%r{^spec/})
25
25
 
@@ -21,7 +21,7 @@ module Bundler
21
21
  rescue UnknownArgumentError => e
22
22
  raise InvalidOption, e.message
23
23
  ensure
24
- options ||= {}
24
+ self.options ||= {}
25
25
  Bundler.ui = UI::Shell.new(options)
26
26
  Bundler.ui.level = "debug" if options["verbose"]
27
27
  end
@@ -232,8 +232,6 @@ module Bundler
232
232
  opts[:system] = true
233
233
  end
234
234
 
235
- opts["no-cache"] ||= opts[:local]
236
-
237
235
  Bundler.settings[:path] = nil if opts[:system]
238
236
  Bundler.settings[:path] = "vendor/bundle" if opts[:deployment]
239
237
  Bundler.settings[:path] = opts["path"] if opts["path"]
@@ -255,7 +253,7 @@ module Bundler
255
253
  definition = Bundler.definition
256
254
  definition.validate_ruby!
257
255
  Installer.install(Bundler.root, definition, opts)
258
- Bundler.load.cache if Bundler.root.join("vendor/cache").exist? && !opts["no-cache"]
256
+ Bundler.load.cache if Bundler.root.join("vendor/cache").exist? && !options["no-cache"]
259
257
 
260
258
  if Bundler.settings[:path]
261
259
  absolute_path = File.expand_path(Bundler.settings[:path])
@@ -226,7 +226,7 @@ module Bundler
226
226
  private
227
227
 
228
228
  HTTP_ERRORS = [
229
- Timeout::Error, EOFError, SocketError,
229
+ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN,
230
230
  Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
231
231
  Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
232
232
  Net::HTTP::Persistent::Error
@@ -235,17 +235,7 @@ module Bundler
235
235
  def fetch(uri, counter = 0)
236
236
  raise HTTPError, "Too many redirects" if counter >= @redirect_limit
237
237
 
238
- begin
239
- Bundler.ui.debug "Fetching from: #{uri}"
240
- req = Net::HTTP::Get.new uri.request_uri
241
- req.basic_auth(uri.user, uri.password) if uri.user
242
- response = connection.request(uri, req)
243
- rescue OpenSSL::SSL::SSLError
244
- raise CertificateFailureError.new(uri)
245
- rescue *HTTP_ERRORS
246
- raise HTTPError, "Network error while fetching #{uri}"
247
- end
248
-
238
+ response = request(uri)
249
239
  case response
250
240
  when Net::HTTPRedirection
251
241
  Bundler.ui.debug("HTTP Redirection")
@@ -265,6 +255,17 @@ module Bundler
265
255
  end
266
256
  end
267
257
 
258
+ def request(uri)
259
+ Bundler.ui.debug "Fetching from: #{uri}"
260
+ req = Net::HTTP::Get.new uri.request_uri
261
+ req.basic_auth(uri.user, uri.password) if uri.user
262
+ response = connection.request(uri, req)
263
+ rescue OpenSSL::SSL::SSLError
264
+ raise CertificateFailureError.new(uri)
265
+ rescue *HTTP_ERRORS
266
+ raise HTTPError, "Network error while fetching #{uri}"
267
+ end
268
+
268
269
  def dependency_api_uri(gem_names = [])
269
270
  url = "#{@remote_uri}api/v1/dependencies"
270
271
  url << "?gems=#{URI.encode(gem_names.join(","))}" if gem_names.any?
@@ -113,7 +113,6 @@ module Bundler
113
113
  Bundler.ui.debug debug_message if debug_message
114
114
  spec_info = "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
115
115
  Bundler.ui.debug spec_info
116
- logger.info spec_info
117
116
  end
118
117
 
119
118
  if Bundler.settings[:bin] && standalone
@@ -139,7 +138,6 @@ module Bundler
139
138
  msg << " #{spec.name} -v '#{spec.version}'` succeeds before bundling."
140
139
  end
141
140
  Bundler.ui.debug e.backtrace.join("\n")
142
- logger.error("#{e.class}: #{e.message}\n#{e.backtrace.join(' \n')}")
143
141
  raise Bundler::InstallError, msg
144
142
  end
145
143
 
@@ -176,7 +174,7 @@ module Bundler
176
174
  next
177
175
  end
178
176
 
179
- File.open(binstub_path, 'w', 0755) do |f|
177
+ File.open(binstub_path, 'w', 0777 & ~File.umask) do |f|
180
178
  f.puts ERB.new(template, nil, '-').result(binding)
181
179
  end
182
180
  end
@@ -198,15 +196,6 @@ module Bundler
198
196
 
199
197
  private
200
198
 
201
- def logger
202
- # Create a debug installation log limited to 1MB
203
- @logger ||= begin
204
- require 'logger'
205
- Bundler.app_config_path.mkpath
206
- Logger.new(Bundler.app_config_path.join("install.log"), 1, 1048576)
207
- end
208
- end
209
-
210
199
  def can_install_parallely?
211
200
  min_rubygems = "2.0.7"
212
201
  if Bundler.current_ruby.mri? || Bundler.rubygems.provides?(">= #{min_rubygems}")
@@ -219,25 +208,6 @@ module Bundler
219
208
  end
220
209
  end
221
210
 
222
- def check_rubygems_cache_dir
223
- require 'digest'
224
- cached_gems = Dir["#{Bundler.rubygems.gem_dir}/cache/*.gem"]
225
-
226
- same_size_gems = cached_gems.group_by { |f| File.size(f) }.
227
- values.select { |names| names.size > 1 }
228
-
229
- same_hash_gems = same_size_gems.flatten.group_by do |f|
230
- Digest::SHA1.hexdigest(File.read(f))
231
- end.values.select { |names| names.size > 1 }
232
-
233
- if same_hash_gems.any?
234
- Bundler.ui.warn "It looks like some of your gems are corrupted!"
235
- same_hash_gems.each { |name| Bundler.ui.warn " * #{name}" }
236
- Bundler.ui.warn "Please report this issue to the Bundler issue tracker " \
237
- "on Github, and include the log file at .bundle/install.log. Thanks!"
238
- end
239
- end
240
-
241
211
  def generate_standalone_bundler_executable_stubs(spec)
242
212
  # double-assignment to avoid warnings about variables that will be used by ERB
243
213
  bin_path = Bundler.bin_path
@@ -314,8 +284,7 @@ module Bundler
314
284
  { :name => spec.name, :post_install => message }
315
285
  }
316
286
  specs.each do |spec|
317
- deps = spec.dependencies.select { |dep| dep.type != :development }
318
- if deps.empty?
287
+ if ready_to_install?(spec, remains)
319
288
  worker_pool.enq spec.name
320
289
  enqueued[spec.name] = true
321
290
  end
@@ -330,17 +299,21 @@ module Bundler
330
299
  remains.keys.each do |name|
331
300
  next if enqueued[name]
332
301
  spec = name2spec[name]
333
- deps = spec.dependencies.select { |dep| remains[dep.name] and dep.type != :development }
334
- if deps.empty?
302
+ if ready_to_install?(spec, remains)
335
303
  worker_pool.enq name
336
304
  enqueued[name] = true
337
305
  end
338
306
  end
339
307
  end
340
- check_rubygems_cache_dir
341
308
  message
342
309
  ensure
343
310
  worker_pool && worker_pool.stop
344
311
  end
312
+
313
+ def ready_to_install?(spec, remains)
314
+ spec.dependencies.none? do |dep|
315
+ remains[dep.name] && dep.type != :development && dep.name != spec.name
316
+ end
317
+ end
345
318
  end
346
319
  end
@@ -80,12 +80,20 @@ module Bundler
80
80
  # Kill the forked workers by sending SIGINT to them
81
81
  def stop_workers
82
82
  @workers.each do |worker|
83
- worker.io_r.close
84
- worker.io_w.close
85
- Process.kill :INT, worker.pid
83
+ worker.io_r.close unless worker.io_r.closed?
84
+ worker.io_w.close unless worker.io_w.closed?
85
+ begin
86
+ Process.kill :INT, worker.pid
87
+ rescue Errno::ESRCH
88
+ nil
89
+ end
86
90
  end
87
91
  @workers.each do |worker|
88
- Process.waitpid worker.pid
92
+ begin
93
+ Process.waitpid worker.pid
94
+ rescue Errno::ECHILD
95
+ nil
96
+ end
89
97
  end
90
98
  end
91
99
  end
@@ -19,6 +19,7 @@ module Bundler
19
19
  @response_queue = Queue.new
20
20
  prepare_workers size, func
21
21
  prepare_threads size
22
+ trap("INT") { @threads.each {|i| i.exit }; stop_workers; exit 1 }
22
23
  end
23
24
 
24
25
  # Enque a request to be executed in the worker pool
@@ -56,7 +56,7 @@ module Gem
56
56
  end
57
57
 
58
58
  def git_version
59
- if @loaded_from && File.exist?(File.join(full_gem_path, ".git"))
59
+ if loaded_from && File.exist?(File.join(full_gem_path, ".git"))
60
60
  sha = Bundler::SharedHelpers.chdir(full_gem_path){ `git rev-parse HEAD`.strip }
61
61
  " #{sha[0..6]}"
62
62
  end
@@ -422,7 +422,7 @@ module Bundler
422
422
  end
423
423
  end
424
424
 
425
- # Rubygems ~> 1.8.5
425
+ # Rubygems 1.8.5-1.8.19
426
426
  class Modern < RubygemsIntegration
427
427
  def stub_rubygems(specs)
428
428
  Gem::Specification.all = specs
@@ -441,11 +441,6 @@ module Bundler
441
441
  def find_name(name)
442
442
  Gem::Specification.find_all_by_name name
443
443
  end
444
-
445
- def build(spec, skip_validation = false)
446
- require 'rubygems/builder'
447
- Gem::Builder.new(spec).build(skip_validation)
448
- end
449
444
  end
450
445
 
451
446
  # Rubygems 1.8.0 to 1.8.4
@@ -460,14 +455,24 @@ module Bundler
460
455
  end
461
456
  end
462
457
 
458
+ # Rubygems 1.8.20+
459
+ class MoreModern < Modern
460
+ # Rubygems 1.8.20 and adds the skip_validation parameter, so that's
461
+ # when we start passing it through.
462
+ def build(spec, skip_validation = false)
463
+ require 'rubygems/builder'
464
+ Gem::Builder.new(spec).build(skip_validation)
465
+ end
466
+ end
467
+
463
468
  # Rubygems 2.0
464
469
  class Future < RubygemsIntegration
465
470
  def stub_rubygems(specs)
466
471
  Gem::Specification.all = specs
467
472
 
468
- Gem.post_reset {
473
+ Gem.post_reset do
469
474
  Gem::Specification.all = specs
470
- }
475
+ end
471
476
  end
472
477
 
473
478
  def all_specs
@@ -529,6 +534,8 @@ module Bundler
529
534
 
530
535
  if RubygemsIntegration.provides?(">= 1.99.99")
531
536
  @rubygems = RubygemsIntegration::Future.new
537
+ elsif RubygemsIntegration.provides?('>= 1.8.20')
538
+ @rubygems = RubygemsIntegration::MoreModern.new
532
539
  elsif RubygemsIntegration.provides?('>= 1.8.5')
533
540
  @rubygems = RubygemsIntegration::Modern.new
534
541
  elsif RubygemsIntegration.provides?('>= 1.8.0')
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
@@ -1,7 +1,7 @@
1
1
  require 'set'
2
2
  require 'thor/base'
3
3
 
4
- class Thor
4
+ class Thor # rubocop:disable ClassLength
5
5
  class << self
6
6
  # Allows for custom "Command" package naming.
7
7
  #
@@ -9,7 +9,7 @@ class Thor
9
9
  # name<String>
10
10
  # options<Hash>
11
11
  #
12
- def package_name(name, options={})
12
+ def package_name(name, options = {})
13
13
  @package_name = name.nil? || name == '' ? nil : name
14
14
  end
15
15
 
@@ -18,17 +18,14 @@ class Thor
18
18
  # ==== Parameters
19
19
  # meth<Symbol>:: name of the default command
20
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')
21
+ def default_command(meth = nil)
22
+ if meth
23
+ @default_command = meth == :none ? 'help' : meth.to_s
27
24
  else
28
- meth.to_s
25
+ @default_command ||= from_superclass(:default_command, 'help')
29
26
  end
30
27
  end
31
- alias default_task default_command
28
+ alias_method :default_task, :default_command
32
29
 
33
30
  # Registers another Thor subclass as a command.
34
31
  #
@@ -37,7 +34,7 @@ class Thor
37
34
  # command<String>:: Subcommand name to use
38
35
  # usage<String>:: Short usage for the subcommand
39
36
  # description<String>:: Description for the subcommand
40
- def register(klass, subcommand_name, usage, description, options={})
37
+ def register(klass, subcommand_name, usage, description, options = {})
41
38
  if klass <= Thor::Group
42
39
  desc usage, description, options
43
40
  define_method(subcommand_name) { |*args| invoke(klass, args) }
@@ -54,7 +51,7 @@ class Thor
54
51
  # description<String>
55
52
  # options<String>
56
53
  #
57
- def desc(usage, description, options={})
54
+ def desc(usage, description, options = {})
58
55
  if options[:for]
59
56
  command = find_and_refresh_command(options[:for])
60
57
  command.usage = usage if usage
@@ -69,7 +66,7 @@ class Thor
69
66
  # ==== Parameters
70
67
  # long description<String>
71
68
  #
72
- def long_desc(long_description, options={})
69
+ def long_desc(long_description, options = {})
73
70
  if options[:for]
74
71
  command = find_and_refresh_command(options[:for])
75
72
  command.long_description = long_description if long_description
@@ -91,13 +88,13 @@ class Thor
91
88
  # ==== Parameters
92
89
  # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
93
90
  #
94
- def map(mappings=nil)
91
+ def map(mappings = nil)
95
92
  @map ||= from_superclass(:map, {})
96
93
 
97
94
  if mappings
98
95
  mappings.each do |key, value|
99
96
  if key.respond_to?(:each)
100
- key.each {|subkey| @map[subkey] = value}
97
+ key.each { |subkey| @map[subkey] = value }
101
98
  else
102
99
  @map[key] = value
103
100
  end
@@ -114,13 +111,13 @@ class Thor
114
111
  # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
115
112
  # or :required (string). If you give a value, the type of the value is used.
116
113
  #
117
- def method_options(options=nil)
114
+ def method_options(options = nil)
118
115
  @method_options ||= {}
119
116
  build_options(options, @method_options) if options
120
117
  @method_options
121
118
  end
122
119
 
123
- alias options method_options
120
+ alias_method :options, :method_options
124
121
 
125
122
  # Adds an option to the set of method options. If :for is given as option,
126
123
  # it allows you to change the options from a previous defined command.
@@ -148,16 +145,16 @@ class Thor
148
145
  # :banner - String to show on usage notes.
149
146
  # :hide - If you want to hide this option from the help.
150
147
  #
151
- def method_option(name, options={})
148
+ def method_option(name, options = {})
152
149
  scope = if options[:for]
153
- find_and_refresh_command(options[:for]).options
154
- else
155
- method_options
156
- end
150
+ find_and_refresh_command(options[:for]).options
151
+ else
152
+ method_options
153
+ end
157
154
 
158
155
  build_option(name, options, scope)
159
156
  end
160
- alias option method_option
157
+ alias_method :option, :method_option
161
158
 
162
159
  # Prints help information for the given command.
163
160
  #
@@ -170,18 +167,18 @@ class Thor
170
167
  command = all_commands[meth]
171
168
  handle_no_command_error(meth) unless command
172
169
 
173
- shell.say "Usage:"
170
+ shell.say 'Usage:'
174
171
  shell.say " #{banner(command)}"
175
172
  shell.say
176
173
  class_options_help(shell, nil => command.options.map { |_, o| o })
177
174
  if command.long_description
178
- shell.say "Description:"
175
+ shell.say 'Description:'
179
176
  shell.print_wrapped(command.long_description, :indent => 2)
180
177
  else
181
178
  shell.say command.description
182
179
  end
183
180
  end
184
- alias task_help command_help
181
+ alias_method :task_help, :command_help
185
182
 
186
183
  # Prints help information for this class.
187
184
  #
@@ -193,12 +190,12 @@ class Thor
193
190
  Thor::Util.thor_classes_in(self).each do |klass|
194
191
  list += klass.printable_commands(false)
195
192
  end
196
- list.sort!{ |a,b| a[0] <=> b[0] }
193
+ list.sort! { |a, b| a[0] <=> b[0] }
197
194
 
198
- if @package_name
195
+ if defined?(@package_name) && @package_name
199
196
  shell.say "#{@package_name} commands:"
200
197
  else
201
- shell.say "Commands:"
198
+ shell.say 'Commands:'
202
199
  end
203
200
 
204
201
  shell.print_table(list, :indent => 2, :truncate => true)
@@ -212,34 +209,35 @@ class Thor
212
209
  next if command.hidden?
213
210
  item = []
214
211
  item << banner(command, false, subcommand)
215
- item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
212
+ item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : '')
216
213
  item
217
214
  end.compact
218
215
  end
219
- alias printable_tasks printable_commands
216
+ alias_method :printable_tasks, :printable_commands
220
217
 
221
218
  def subcommands
222
219
  @subcommands ||= from_superclass(:subcommands, [])
223
220
  end
224
- alias subtasks subcommands
221
+ alias_method :subtasks, :subcommands
225
222
 
226
223
  def subcommand(subcommand, subcommand_class)
227
- self.subcommands << subcommand.to_s
224
+ subcommands << subcommand.to_s
228
225
  subcommand_class.subcommand_help subcommand
229
226
 
230
227
  define_method(subcommand) do |*args|
231
228
  args, opts = Thor::Arguments.split(args)
229
+ args.unshift("help") if opts.include? "--help" or opts.include? "-h"
232
230
  invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
233
231
  end
234
232
  end
235
- alias subtask subcommand
233
+ alias_method :subtask, :subcommand
236
234
 
237
235
  # Extend check unknown options to accept a hash of conditions.
238
236
  #
239
237
  # === Parameters
240
238
  # options<Hash>: A hash containing :only and/or :except keys
241
- def check_unknown_options!(options={})
242
- @check_unknown_options ||= Hash.new
239
+ def check_unknown_options!(options = {})
240
+ @check_unknown_options ||= {}
243
241
  options.each do |key, value|
244
242
  if value
245
243
  @check_unknown_options[key] = Array(value)
@@ -309,18 +307,20 @@ class Thor
309
307
  # ==== Parameters
310
308
  # Symbol ...:: A list of commands that should be affected.
311
309
  def stop_on_unknown_option!(*command_names)
312
- @stop_on_unknown_option ||= Set.new
313
- @stop_on_unknown_option.merge(command_names)
310
+ stop_on_unknown_option.merge(command_names)
314
311
  end
315
312
 
316
313
  def stop_on_unknown_option?(command) #:nodoc:
317
- command && !@stop_on_unknown_option.nil? && @stop_on_unknown_option.include?(command.name.to_sym)
314
+ command && stop_on_unknown_option.include?(command.name.to_sym)
318
315
  end
319
316
 
320
317
  protected
318
+ def stop_on_unknown_option #:nodoc:
319
+ @stop_on_unknown_option ||= Set.new
320
+ end
321
321
 
322
322
  # The method responsible for dispatching given the args.
323
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
323
+ def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
324
324
  # There is an edge case when dispatching from a subcommand.
325
325
  # A problem occurs invoking the default command. This case occurs
326
326
  # when arguments are passed and a default command is defined, and
@@ -331,7 +331,7 @@ class Thor
331
331
  # the command normally. If the first item in given_args is not
332
332
  # a command then use the default command. The given_args will be
333
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
334
+ if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != 'help' && given_args.first != default_command
335
335
  meth ||= retrieve_command_name(given_args.dup)
336
336
  command = all_commands[normalize_command_name(meth)]
337
337
  command ||= all_commands[normalize_command_name(default_command)]
@@ -350,7 +350,7 @@ class Thor
350
350
  end
351
351
  else
352
352
  args, opts = given_args, nil
353
- command = Thor::DynamicCommand.new(meth)
353
+ command = dynamic_command_class.new(meth)
354
354
  end
355
355
 
356
356
  opts = given_opts || opts || []
@@ -376,22 +376,30 @@ class Thor
376
376
  Thor
377
377
  end
378
378
 
379
+ def dynamic_command_class #:nodoc:
380
+ Thor::DynamicCommand
381
+ end
382
+
379
383
  def create_command(meth) #:nodoc:
384
+ @usage ||= nil
385
+ @desc ||= nil
386
+ @long_desc ||= nil
387
+
380
388
  if @usage && @desc
381
389
  base_class = @hide ? Thor::HiddenCommand : Thor::Command
382
390
  commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
383
391
  @usage, @desc, @long_desc, @method_options, @hide = nil
384
392
  true
385
- elsif self.all_commands[meth] || meth == "method_missing"
393
+ elsif all_commands[meth] || meth == 'method_missing'
386
394
  true
387
395
  else
388
396
  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 " <<
397
+ 'Call desc if you want this method to be available as command or declare it inside a ' <<
390
398
  "no_commands{} block. Invoked from #{caller[1].inspect}."
391
399
  false
392
400
  end
393
401
  end
394
- alias create_task create_command
402
+ alias_method :create_task, :create_command
395
403
 
396
404
  def initialize_added #:nodoc:
397
405
  class_options.merge!(method_options)
@@ -407,7 +415,7 @@ class Thor
407
415
  nil
408
416
  end
409
417
  end
410
- alias retrieve_task_name retrieve_command_name
418
+ alias_method :retrieve_task_name, :retrieve_command_name
411
419
 
412
420
  # receives a (possibly nil) command name and returns a name that is in
413
421
  # the commands hash. In addition to normalizing aliases, this logic
@@ -421,7 +429,7 @@ class Thor
421
429
 
422
430
  possibilities = find_command_possibilities(meth)
423
431
  if possibilities.size > 1
424
- raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
432
+ fail AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
425
433
  elsif possibilities.size < 1
426
434
  meth = meth || default_command
427
435
  elsif map[meth]
@@ -430,9 +438,9 @@ class Thor
430
438
  meth = possibilities.first
431
439
  end
432
440
 
433
- meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
441
+ meth.to_s.gsub('-', '_') # treat foo-bar as foo_bar
434
442
  end
435
- alias normalize_task_name normalize_command_name
443
+ alias_method :normalize_task_name, :normalize_command_name
436
444
 
437
445
  # this is the logic that takes the command name passed in by the user
438
446
  # and determines whether it is an unambiguous substrings of a command or
@@ -450,23 +458,22 @@ class Thor
450
458
  possibilities
451
459
  end
452
460
  end
453
- alias find_task_possibilities find_command_possibilities
461
+ alias_method :find_task_possibilities, :find_command_possibilities
454
462
 
455
463
  def subcommand_help(cmd)
456
- desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
457
- class_eval <<-RUBY
464
+ desc 'help [COMMAND]', 'Describe subcommands or one specific subcommand'
465
+ class_eval "
458
466
  def help(command = nil, subcommand = true); super; end
459
- RUBY
467
+ "
460
468
  end
461
- alias subtask_help subcommand_help
462
-
469
+ alias_method :subtask_help, :subcommand_help
463
470
  end
464
471
 
465
472
  include Thor::Base
466
473
 
467
474
  map HELP_MAPPINGS => :help
468
475
 
469
- desc "help [COMMAND]", "Describe available commands or one specific command"
476
+ desc 'help [COMMAND]', 'Describe available commands or one specific command'
470
477
  def help(command = nil, subcommand = false)
471
478
  command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
472
479
  end