bundler 1.1.pre.5 → 1.1.pre.7

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 (66) hide show
  1. data/CHANGELOG.md +52 -1
  2. data/ISSUES.md +1 -0
  3. data/Rakefile +3 -3
  4. data/UPGRADING.md +2 -2
  5. data/lib/bundler/cli.rb +6 -5
  6. data/lib/bundler/definition.rb +13 -2
  7. data/lib/bundler/endpoint_specification.rb +19 -0
  8. data/lib/bundler/fetcher.rb +34 -2
  9. data/lib/bundler/gem_helper.rb +6 -4
  10. data/lib/bundler/index.rb +29 -4
  11. data/lib/bundler/installer.rb +2 -1
  12. data/lib/bundler/lazy_specification.rb +4 -2
  13. data/lib/bundler/resolver.rb +14 -16
  14. data/lib/bundler/rubygems_ext.rb +1 -0
  15. data/lib/bundler/rubygems_integration.rb +22 -2
  16. data/lib/bundler/runtime.rb +2 -0
  17. data/lib/bundler/source.rb +52 -44
  18. data/lib/bundler/spec_set.rb +10 -9
  19. data/lib/bundler/templates/newgem/Rakefile.tt +1 -1
  20. data/lib/bundler/templates/newgem/newgem.gemspec.tt +2 -2
  21. data/lib/bundler/vendor/thor.rb +43 -4
  22. data/lib/bundler/vendor/thor/actions.rb +28 -11
  23. data/lib/bundler/vendor/thor/actions/create_file.rb +2 -2
  24. data/lib/bundler/vendor/thor/actions/create_link.rb +57 -0
  25. data/lib/bundler/vendor/thor/actions/directory.rb +2 -2
  26. data/lib/bundler/vendor/thor/actions/empty_directory.rb +0 -0
  27. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +56 -15
  28. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +13 -8
  29. data/lib/bundler/vendor/thor/base.rb +24 -4
  30. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +0 -0
  31. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +0 -0
  32. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +0 -0
  33. data/lib/bundler/vendor/thor/error.rb +0 -0
  34. data/lib/bundler/vendor/thor/group.rb +273 -0
  35. data/lib/bundler/vendor/thor/invocation.rb +0 -0
  36. data/lib/bundler/vendor/thor/parser.rb +0 -0
  37. data/lib/bundler/vendor/thor/parser/argument.rb +0 -0
  38. data/lib/bundler/vendor/thor/parser/arguments.rb +2 -2
  39. data/lib/bundler/vendor/thor/parser/option.rb +0 -0
  40. data/lib/bundler/vendor/thor/parser/options.rb +17 -16
  41. data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
  42. data/lib/bundler/vendor/thor/runner.rb +309 -0
  43. data/lib/bundler/vendor/thor/shell.rb +0 -0
  44. data/lib/bundler/vendor/thor/shell/basic.rb +40 -13
  45. data/lib/bundler/vendor/thor/shell/color.rb +0 -0
  46. data/lib/bundler/vendor/thor/task.rb +3 -4
  47. data/lib/bundler/vendor/thor/util.rb +2 -2
  48. data/lib/bundler/vendor/thor/version.rb +1 -1
  49. data/lib/bundler/version.rb +1 -1
  50. data/man/gemfile.5.ronn +3 -0
  51. data/spec/cache/git_spec.rb +5 -2
  52. data/spec/install/gems/dependency_api_spec.rb +69 -0
  53. data/spec/install/gems/simple_case_spec.rb +7 -0
  54. data/spec/install/gems/standalone_spec.rb +62 -0
  55. data/spec/install/git_spec.rb +63 -1
  56. data/spec/other/clean_spec.rb +22 -26
  57. data/spec/other/exec_spec.rb +2 -2
  58. data/spec/other/gem_helper_spec.rb +1 -1
  59. data/spec/runtime/setup_spec.rb +1 -1
  60. data/spec/support/artifice/endpoint.rb +2 -2
  61. data/spec/support/artifice/endpoint_api_missing.rb +16 -0
  62. data/spec/support/artifice/endpoint_extra.rb +27 -0
  63. data/spec/support/artifice/endpoint_extra_missing.rb +15 -0
  64. data/spec/support/helpers.rb +7 -6
  65. metadata +73 -40
  66. data/spec/pack/gems_spec.rb +0 -22
@@ -141,6 +141,7 @@ module Gem
141
141
 
142
142
  alias eql? ==
143
143
  end
144
+
144
145
  end
145
146
 
146
147
  module Bundler
@@ -250,7 +250,17 @@ module Bundler
250
250
  Gem.clear_paths
251
251
  end
252
252
 
253
- # Rubygems versions 1.3.6 through 1.6.2
253
+ # This backports the correct segment generation code from Rubygems 1.4+
254
+ # by monkeypatching it into the method in Rubygems 1.3.6 and 1.3.7.
255
+ def backport_segment_generation
256
+ Gem::Version.send(:define_method, :segments) do
257
+ @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
258
+ /^\d+$/ =~ s ? s.to_i : s
259
+ end
260
+ end
261
+ end
262
+
263
+ # Rubygems 1.4 through 1.6
254
264
  class Legacy < RubygemsIntegration
255
265
  def stub_rubygems(specs)
256
266
  stub_source_index137(specs)
@@ -265,6 +275,14 @@ module Bundler
265
275
  end
266
276
  end
267
277
 
278
+ # Rubygems versions 1.3.6 and 1.3.7
279
+ class Ancient < Legacy
280
+ def initialize
281
+ super
282
+ backport_segment_generation
283
+ end
284
+ end
285
+
268
286
  # Rubygems 1.7
269
287
  class Transitional < Legacy
270
288
  def stub_rubygems(specs)
@@ -313,8 +331,10 @@ module Bundler
313
331
  @rubygems = RubygemsIntegration::AlmostModern.new
314
332
  elsif Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.7.0')
315
333
  @rubygems = RubygemsIntegration::Transitional.new
316
- else # Rubygems 1.3.6 through 1.6.2
334
+ elsif Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.4.0')
317
335
  @rubygems = RubygemsIntegration::Legacy.new
336
+ else # Rubygems 1.3.6 and 1.3.7
337
+ @rubygems = RubygemsIntegration::Ancient.new
318
338
  end
319
339
 
320
340
  class << self
@@ -142,6 +142,8 @@ module Bundler
142
142
  FileUtils.rm_rf(gem_dir)
143
143
  specification_file = "#{Gem.dir}/specifications/#{full_name}.gemspec"
144
144
  FileUtils.rm(specification_file) if File.exists?(specification_file)
145
+ gem_file = "#{Gem.dir}/cache/#{full_name}.gem"
146
+ FileUtils.rm(gem_file) if File.exists?(gem_file)
145
147
 
146
148
  parts = full_name.split('-')
147
149
  name = parts[0..-2].join('-')
@@ -10,8 +10,10 @@ module Bundler
10
10
  module Source
11
11
  # TODO: Refactor this class
12
12
  class Rubygems
13
+ FORCE_MODERN_INDEX_LIMIT = 100 # threshold for switching back to the modern index instead of fetching every spec
14
+
13
15
  attr_reader :remotes, :caches
14
- attr_accessor :dependencies
16
+ attr_accessor :dependency_names
15
17
 
16
18
  def initialize(options = {})
17
19
  @options = options
@@ -22,8 +24,6 @@ module Bundler
22
24
 
23
25
  @caches = [ Bundler.app_cache ] +
24
26
  Bundler.rubygems.gem_path.map{|p| File.expand_path("#{p}/cache") }
25
-
26
- @spec_fetch_map = {}
27
27
  end
28
28
 
29
29
  def remote!
@@ -70,15 +70,6 @@ module Bundler
70
70
  @specs ||= fetch_specs
71
71
  end
72
72
 
73
- def fetch(spec)
74
- spec, uri = @spec_fetch_map[spec.full_name]
75
- if spec
76
- path = download_gem_from_uri(spec, uri)
77
- s = Bundler.rubygems.spec_from_gem(path)
78
- spec.__swap__(s) if spec.is_a?(RemoteSpecification)
79
- end
80
- end
81
-
82
73
  def install(spec)
83
74
  if installed_specs[spec].any?
84
75
  Bundler.ui.info "Using #{spec.name} (#{spec.version}) "
@@ -107,22 +98,18 @@ module Bundler
107
98
 
108
99
  # SUDO HAX
109
100
  if Bundler.requires_sudo?
110
- sudo "mkdir -p #{Bundler.rubygems.gem_dir}/gems #{Bundler.rubygems.gem_dir}/specifications"
111
- sudo "cp -R #{Bundler.tmp}/gems/#{spec.full_name} #{Bundler.rubygems.gem_dir}/gems/"
112
- sudo "cp -R #{Bundler.tmp}/specifications/#{spec.full_name}.gemspec #{Bundler.rubygems.gem_dir}/specifications/"
101
+ Bundler.sudo "mkdir -p #{Bundler.rubygems.gem_dir}/gems #{Bundler.rubygems.gem_dir}/specifications"
102
+ Bundler.sudo "cp -R #{Bundler.tmp}/gems/#{spec.full_name} #{Bundler.rubygems.gem_dir}/gems/"
103
+ Bundler.sudo "cp -R #{Bundler.tmp}/specifications/#{spec.full_name}.gemspec #{Bundler.rubygems.gem_dir}/specifications/"
113
104
  spec.executables.each do |exe|
114
- sudo "mkdir -p #{Bundler.rubygems.gem_bindir}"
115
- sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_bindir}"
105
+ Bundler.sudo "mkdir -p #{Bundler.rubygems.gem_bindir}"
106
+ Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_bindir}"
116
107
  end
117
108
  end
118
109
 
119
110
  spec.loaded_from = "#{Bundler.rubygems.gem_dir}/specifications/#{spec.full_name}.gemspec"
120
111
  end
121
112
 
122
- def sudo(str)
123
- Bundler.sudo(str)
124
- end
125
-
126
113
  def cache(spec)
127
114
  cached_path = cached_gem(spec)
128
115
  raise GemNotFound, "Missing gem file '#{spec.full_name}.gem'." unless cached_path
@@ -226,35 +213,41 @@ module Bundler
226
213
  idx = Index.new
227
214
  old = Bundler.rubygems.sources
228
215
 
216
+ sources = {}
229
217
  remotes.each do |uri|
218
+ fetcher = Bundler::Fetcher.new(uri)
219
+ specs = fetcher.specs(dependency_names, self)
220
+ sources[fetcher] = specs.size
230
221
 
231
- @fetchers[uri] = Bundler::Fetcher.new(uri)
232
- gem_names = dependencies && dependencies.map{|d| d.name }
222
+ idx.use specs
223
+ end
233
224
 
234
- idx.use @fetchers[uri].specs(gem_names, self, @spec_fetch_map)
225
+ # don't need to fetch all specifications for every gem/version on
226
+ # the rubygems repo if there's no api endpoints to search over
227
+ # or it has too many specs to fetch
228
+ fetchers = sources.keys
229
+ api_fetchers = fetchers.select {|fetcher| fetcher.has_api }
230
+ modern_index_fetchers = fetchers - api_fetchers
231
+ if api_fetchers.any? && modern_index_fetchers.all? {|fetcher| sources[fetcher] < FORCE_MODERN_INDEX_LIMIT }
232
+ # this will fetch all the specifications on the rubygems repo
233
+ unmet_dependency_names = idx.unmet_dependency_names
234
+
235
+ if unmet_dependency_names.any?
236
+ api_fetchers.each do |fetcher|
237
+ idx.use fetcher.specs(unmet_dependency_names, self)
238
+ end
239
+ end
240
+ else
241
+ Bundler::Fetcher.disable_endpoint = true
242
+ api_fetchers.each {|fetcher| idx.use fetcher.specs([], self) }
235
243
  end
244
+
236
245
  idx
237
246
  ensure
238
247
  Bundler.rubygems.sources = old
239
248
  end
240
249
  end
241
250
 
242
- def download_gem_from_uri(spec, uri)
243
- spec.fetch_platform
244
-
245
- download_path = Bundler.requires_sudo? ? Bundler.tmp : Bundler.rubygems.gem_dir
246
- gem_path = "#{Bundler.rubygems.gem_dir}/cache/#{spec.full_name}.gem"
247
-
248
- FileUtils.mkdir_p("#{download_path}/cache")
249
- Bundler.rubygems.download_gem(spec, uri, download_path)
250
-
251
- if Bundler.requires_sudo?
252
- sudo "mkdir -p #{Bundler.rubygems.gem_dir}/cache"
253
- sudo "mv #{Bundler.tmp}/cache/#{spec.full_name}.gem #{gem_path}"
254
- end
255
-
256
- gem_path
257
- end
258
251
  end
259
252
 
260
253
  class Path
@@ -345,9 +338,9 @@ module Bundler
345
338
  s.relative_loaded_from = "#{@name}.gemspec"
346
339
  s.authors = ["no one"]
347
340
  if expanded_path.join("bin").exist?
348
- binaries = expanded_path.join("bin").children
349
- binaries.reject!{|p| File.directory?(p) }
350
- s.executables = binaries.map{|c| c.basename.to_s }
341
+ executables = expanded_path.join("bin").children
342
+ executables.reject!{|p| File.directory?(p) }
343
+ s.executables = executables.map{|c| c.basename.to_s }
351
344
  end
352
345
  end
353
346
  end
@@ -433,8 +426,11 @@ module Bundler
433
426
  gem_file = Dir.chdir(gem_dir){ Gem::Builder.new(spec).build }
434
427
 
435
428
  installer = Installer.new(spec, :env_shebang => false)
429
+ run_hooks(:pre_install, installer)
436
430
  installer.build_extensions
431
+ run_hooks(:post_build, installer)
437
432
  installer.generate_bin
433
+ run_hooks(:post_install, installer)
438
434
  rescue Gem::InvalidSpecificationException => e
439
435
  Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \
440
436
  "This prevents bundler from installing bins or native extensions, but " \
@@ -451,6 +447,18 @@ module Bundler
451
447
  Dir.chdir(gem_dir){ FileUtils.rm_rf(gem_file) if gem_file && File.exist?(gem_file) }
452
448
  end
453
449
 
450
+ def run_hooks(type, installer)
451
+ hooks_meth = "#{type}_hooks"
452
+ return unless Gem.respond_to?(hooks_meth)
453
+ Gem.send(hooks_meth).each do |hook|
454
+ result = hook.call(installer)
455
+ if result == false
456
+ location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
457
+ message = "#{type} hook#{location} failed for #{installer.spec.full_name}"
458
+ raise Gem::InstallError, message
459
+ end
460
+ end
461
+ end
454
462
  end
455
463
 
456
464
  class Git < Path
@@ -568,7 +576,7 @@ module Bundler
568
576
  end
569
577
 
570
578
  def base_name
571
- File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)},''), ".git")
579
+ File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*},''),".git")
572
580
  end
573
581
 
574
582
  def shortref_for_display(ref)
@@ -1,21 +1,18 @@
1
1
  require 'tsort'
2
+ require 'forwardable'
2
3
 
3
4
  module Bundler
4
5
  class SpecSet
6
+ extend Forwardable
5
7
  include TSort, Enumerable
6
8
 
9
+ def_delegators :@specs, :<<, :length, :add, :remove
10
+ def_delegators :sorted, :each
11
+
7
12
  def initialize(specs)
8
13
  @specs = specs.sort_by { |s| s.name }
9
14
  end
10
15
 
11
- def each
12
- sorted.each { |s| yield s }
13
- end
14
-
15
- def length
16
- @specs.length
17
- end
18
-
19
16
  def for(dependencies, skip = [], check = false, match_current_platform = false)
20
17
  handled, deps, specs = {}, dependencies.dup, []
21
18
  skip << 'bundler'
@@ -68,6 +65,10 @@ module Bundler
68
65
  value
69
66
  end
70
67
 
68
+ def sort!
69
+ self
70
+ end
71
+
71
72
  def to_a
72
73
  sorted.dup
73
74
  end
@@ -80,7 +81,7 @@ module Bundler
80
81
  materialized = self.for(deps, [], false, true).to_a
81
82
  materialized.map! do |s|
82
83
  next s unless s.is_a?(LazySpecification)
83
- s.source.dependencies = deps if s.source.respond_to?(:dependencies=)
84
+ s.source.dependency_names = deps.map {|d| d.name } if s.source.respond_to?(:dependency_names=)
84
85
  spec = s.__materialize__
85
86
  if missing_specs
86
87
  missing_specs << s unless spec
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env rake
2
- require 'bundler/gem_tasks'
2
+ require "bundler/gem_tasks"
@@ -6,12 +6,12 @@ Gem::Specification.new do |gem|
6
6
  gem.email = [<%=config[:email].inspect%>]
7
7
  gem.description = %q{TODO: Write a gem description}
8
8
  gem.summary = %q{TODO: Write a gem summary}
9
- gem.homepage = ''
9
+ gem.homepage = ""
10
10
 
11
11
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
12
  gem.files = `git ls-files`.split("\n")
13
13
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
14
  gem.name = <%=config[:name].inspect%>
15
- gem.require_paths = ['lib']
15
+ gem.require_paths = ["lib"]
16
16
  gem.version = <%=config[:constant_name]%>::VERSION
17
17
  end
@@ -18,6 +18,23 @@ class Thor
18
18
  end
19
19
  end
20
20
 
21
+ # Registers another Thor subclass as a command.
22
+ #
23
+ # ==== Parameters
24
+ # klass<Class>:: Thor subclass to register
25
+ # command<String>:: Subcommand name to use
26
+ # usage<String>:: Short usage for the subcommand
27
+ # description<String>:: Description for the subcommand
28
+ def register(klass, subcommand_name, usage, description, options={})
29
+ if klass <= Thor::Group
30
+ desc usage, description, options
31
+ define_method(subcommand_name) { invoke klass }
32
+ else
33
+ desc usage, description, options
34
+ subcommand subcommand_name, klass
35
+ end
36
+ end
37
+
21
38
  # Defines the usage and the description of the next task.
22
39
  #
23
40
  # ==== Parameters
@@ -252,8 +269,7 @@ class Thor
252
269
  # the namespace should be displayed as arguments.
253
270
  #
254
271
  def banner(task, namespace = nil, subcommand = false)
255
- base = File.basename($0).split(" ").first
256
- "#{base} #{task.formatted_usage(self, $thor_runner, subcommand)}"
272
+ "#{basename} #{task.formatted_usage(self, $thor_runner, subcommand)}"
257
273
  end
258
274
 
259
275
  def baseclass #:nodoc:
@@ -295,17 +311,40 @@ class Thor
295
311
  # Receives a task name (can be nil), and try to get a map from it.
296
312
  # If a map can't be found use the sent name or the default task.
297
313
  def normalize_task_name(meth) #:nodoc:
298
- meth = map[meth.to_s] || meth || default_task
314
+ meth = map[meth.to_s] || find_subcommand_and_update_argv(meth) || meth || default_task
299
315
  meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
300
316
  end
301
317
 
318
+ # terrible hack that overwrites ARGV
319
+ def find_subcommand_and_update_argv(subcmd_name) #:nodoc:
320
+ return unless subcmd_name
321
+ cmd = find_subcommand(subcmd_name)
322
+ ARGV[0] = cmd if cmd
323
+ cmd
324
+ end
325
+
326
+ def find_subcommand(subcmd_name)
327
+ possibilities = find_subcommand_possibilities subcmd_name
328
+ if possibilities.size > 1
329
+ raise "Ambiguous subcommand #{subcmd_name} matches [#{possibilities.join(', ')}]"
330
+ elsif possibilities.size < 1
331
+ return nil
332
+ end
333
+
334
+ possibilities.first
335
+ end
336
+
337
+ def find_subcommand_possibilities(subcmd_name)
338
+ len = subcmd_name.length
339
+ all_tasks.map {|t| t.first}.select { |n| subcmd_name == n[0, len] }
340
+ end
341
+
302
342
  def subcommand_help(cmd)
303
343
  desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
304
344
  class_eval <<-RUBY
305
345
  def help(task = nil, subcommand = true); super; end
306
346
  RUBY
307
347
  end
308
-
309
348
  end
310
349
 
311
350
  include Thor::Base
@@ -1,10 +1,12 @@
1
1
  require 'fileutils'
2
2
  require 'uri'
3
3
  require 'thor/core_ext/file_binary_read'
4
-
5
- Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
6
- require action
7
- end
4
+ require 'thor/actions/create_file'
5
+ require 'thor/actions/create_link'
6
+ require 'thor/actions/directory'
7
+ require 'thor/actions/empty_directory'
8
+ require 'thor/actions/file_manipulation'
9
+ require 'thor/actions/inject_into_file'
8
10
 
9
11
  class Thor
10
12
  module Actions
@@ -158,13 +160,23 @@ class Thor
158
160
  #
159
161
  def inside(dir='', config={}, &block)
160
162
  verbose = config.fetch(:verbose, false)
163
+ pretend = options[:pretend]
161
164
 
162
165
  say_status :inside, dir, verbose
163
166
  shell.padding += 1 if verbose
164
167
  @destination_stack.push File.expand_path(dir, destination_root)
165
168
 
166
- FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
167
- FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
169
+ # If the directory doesnt exist and we're not pretending
170
+ if !File.exist?(destination_root) && !pretend
171
+ FileUtils.mkdir_p(destination_root)
172
+ end
173
+
174
+ if pretend
175
+ # In pretend mode, just yield down to the block
176
+ block.arity == 1 ? yield(destination_root) : yield
177
+ else
178
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
179
+ end
168
180
 
169
181
  @destination_stack.pop
170
182
  shell.padding -= 1 if verbose
@@ -210,7 +222,7 @@ class Thor
210
222
  #
211
223
  # ==== Parameters
212
224
  # command<String>:: the command to be executed.
213
- # config<Hash>:: give :verbose => false to not log the status. Specify :with
225
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
214
226
  # to append an executable to command executation.
215
227
  #
216
228
  # ==== Example
@@ -231,7 +243,10 @@ class Thor
231
243
  end
232
244
 
233
245
  say_status :run, desc, config.fetch(:verbose, true)
234
- `#{command}` unless options[:pretend]
246
+
247
+ unless options[:pretend]
248
+ config[:capture] ? `#{command}` : system("#{command}")
249
+ end
235
250
  end
236
251
 
237
252
  # Executes a ruby script (taking into account WIN32 platform quirks).
@@ -251,8 +266,9 @@ class Thor
251
266
  # ==== Parameters
252
267
  # task<String>:: the task to be invoked
253
268
  # args<Array>:: arguments to the task
254
- # config<Hash>:: give :verbose => false to not log the status. Other options
255
- # are given as parameter to Thor.
269
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
270
+ # Other options are given as parameter to Thor.
271
+ #
256
272
  #
257
273
  # ==== Examples
258
274
  #
@@ -266,12 +282,13 @@ class Thor
266
282
  config = args.last.is_a?(Hash) ? args.pop : {}
267
283
  verbose = config.key?(:verbose) ? config.delete(:verbose) : true
268
284
  pretend = config.key?(:pretend) ? config.delete(:pretend) : false
285
+ capture = config.key?(:capture) ? config.delete(:capture) : false
269
286
 
270
287
  args.unshift task
271
288
  args.push Thor::Options.to_switches(config)
272
289
  command = args.join(' ').strip
273
290
 
274
- run command, :with => :thor, :verbose => verbose, :pretend => pretend
291
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
275
292
  end
276
293
 
277
294
  protected