rubygems-update 2.1.11 → 2.2.0.rc.1

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

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.autotest +37 -12
  5. data/History.txt +99 -2
  6. data/MIT.txt +1 -0
  7. data/Manifest.txt +59 -19
  8. data/Rakefile +4 -6
  9. data/lib/gauntlet_rubygems.rb +1 -1
  10. data/lib/rubygems.rb +102 -80
  11. data/lib/rubygems/available_set.rb +2 -2
  12. data/lib/rubygems/basic_specification.rb +97 -8
  13. data/lib/rubygems/commands/install_command.rb +58 -15
  14. data/lib/rubygems/commands/list_command.rb +1 -7
  15. data/lib/rubygems/commands/outdated_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +14 -1
  17. data/lib/rubygems/commands/push_command.rb +9 -4
  18. data/lib/rubygems/commands/query_command.rb +33 -17
  19. data/lib/rubygems/commands/search_command.rb +0 -6
  20. data/lib/rubygems/commands/specification_command.rb +1 -1
  21. data/lib/rubygems/commands/unpack_command.rb +1 -1
  22. data/lib/rubygems/commands/update_command.rb +4 -1
  23. data/lib/rubygems/commands/which_command.rb +5 -8
  24. data/lib/rubygems/compatibility.rb +3 -0
  25. data/lib/rubygems/core_ext/kernel_gem.rb +6 -0
  26. data/lib/rubygems/defaults.rb +19 -0
  27. data/lib/rubygems/dependency_installer.rb +28 -9
  28. data/lib/rubygems/doctor.rb +17 -11
  29. data/lib/rubygems/errors.rb +16 -3
  30. data/lib/rubygems/exceptions.rb +52 -5
  31. data/lib/rubygems/ext.rb +1 -2
  32. data/lib/rubygems/ext/build_error.rb +6 -0
  33. data/lib/rubygems/ext/builder.rb +50 -17
  34. data/lib/rubygems/ext/cmake_builder.rb +1 -1
  35. data/lib/rubygems/ext/configure_builder.rb +1 -3
  36. data/lib/rubygems/ext/ext_conf_builder.rb +9 -3
  37. data/lib/rubygems/ext/rake_builder.rb +2 -5
  38. data/lib/rubygems/gemcutter_utilities.rb +8 -1
  39. data/lib/rubygems/installer.rb +14 -4
  40. data/lib/rubygems/installer_test_case.rb +0 -5
  41. data/lib/rubygems/package.rb +11 -2
  42. data/lib/rubygems/psych_additions.rb +1 -1
  43. data/lib/rubygems/rdoc.rb +1 -1
  44. data/lib/rubygems/remote_fetcher.rb +3 -3
  45. data/lib/rubygems/request.rb +16 -8
  46. data/lib/rubygems/request_set.rb +133 -42
  47. data/lib/rubygems/request_set/gem_dependency_api.rb +493 -11
  48. data/lib/rubygems/request_set/lockfile.rb +579 -0
  49. data/lib/rubygems/requirement.rb +58 -30
  50. data/lib/rubygems/resolver.rb +471 -0
  51. data/lib/rubygems/resolver/activation_request.rb +165 -0
  52. data/lib/rubygems/resolver/api_set.rb +110 -0
  53. data/lib/rubygems/resolver/api_specification.rb +79 -0
  54. data/lib/rubygems/resolver/best_set.rb +31 -0
  55. data/lib/rubygems/resolver/composed_set.rb +39 -0
  56. data/lib/rubygems/resolver/conflict.rb +122 -0
  57. data/lib/rubygems/{dependency_resolver → resolver}/current_set.rb +1 -4
  58. data/lib/rubygems/{dependency_resolver → resolver}/dependency_request.rb +37 -7
  59. data/lib/rubygems/resolver/git_set.rb +119 -0
  60. data/lib/rubygems/resolver/git_specification.rb +35 -0
  61. data/lib/rubygems/resolver/index_set.rb +74 -0
  62. data/lib/rubygems/resolver/index_specification.rb +69 -0
  63. data/lib/rubygems/resolver/installed_specification.rb +40 -0
  64. data/lib/rubygems/{dependency_resolver → resolver}/installer_set.rb +18 -17
  65. data/lib/rubygems/resolver/local_specification.rb +16 -0
  66. data/lib/rubygems/resolver/lock_set.rb +78 -0
  67. data/lib/rubygems/resolver/lock_specification.rb +58 -0
  68. data/lib/rubygems/resolver/requirement_list.rb +81 -0
  69. data/lib/rubygems/resolver/set.rb +27 -0
  70. data/lib/rubygems/resolver/spec_specification.rb +58 -0
  71. data/lib/rubygems/resolver/specification.rb +89 -0
  72. data/lib/rubygems/resolver/stats.rb +44 -0
  73. data/lib/rubygems/resolver/vendor_set.rb +83 -0
  74. data/lib/rubygems/resolver/vendor_specification.rb +24 -0
  75. data/lib/rubygems/security/trust_dir.rb +16 -2
  76. data/lib/rubygems/source.rb +71 -18
  77. data/lib/rubygems/source/git.rb +218 -0
  78. data/lib/rubygems/source/installed.rb +8 -1
  79. data/lib/rubygems/source/local.rb +14 -8
  80. data/lib/rubygems/source/lock.rb +48 -0
  81. data/lib/rubygems/source/specific_file.rb +14 -3
  82. data/lib/rubygems/source/vendor.rb +27 -0
  83. data/lib/rubygems/source_list.rb +74 -12
  84. data/lib/rubygems/spec_fetcher.rb +36 -4
  85. data/lib/rubygems/specification.rb +214 -65
  86. data/lib/rubygems/stub_specification.rb +57 -1
  87. data/lib/rubygems/syck_hack.rb +3 -3
  88. data/lib/rubygems/test_case.rb +226 -59
  89. data/lib/rubygems/test_utilities.rb +198 -0
  90. data/lib/rubygems/uninstaller.rb +22 -10
  91. data/lib/rubygems/uri_formatter.rb +20 -0
  92. data/lib/rubygems/user_interaction.rb +193 -71
  93. data/lib/rubygems/util.rb +121 -0
  94. data/lib/rubygems/util/list.rb +4 -0
  95. data/lib/rubygems/util/stringio.rb +34 -0
  96. data/lib/rubygems/validator.rb +6 -2
  97. data/lib/rubygems/version.rb +4 -8
  98. data/test/rubygems/test_bundled_ca.rb +1 -1
  99. data/test/rubygems/test_gem.rb +137 -29
  100. data/test/rubygems/test_gem_available_set.rb +19 -0
  101. data/test/rubygems/test_gem_commands_build_command.rb +1 -1
  102. data/test/rubygems/test_gem_commands_cert_command.rb +2 -2
  103. data/test/rubygems/test_gem_commands_cleanup_command.rb +13 -13
  104. data/test/rubygems/test_gem_commands_dependency_command.rb +24 -34
  105. data/test/rubygems/test_gem_commands_fetch_command.rb +43 -48
  106. data/test/rubygems/test_gem_commands_install_command.rb +244 -279
  107. data/test/rubygems/test_gem_commands_list_command.rb +3 -3
  108. data/test/rubygems/test_gem_commands_outdated_command.rb +7 -12
  109. data/test/rubygems/test_gem_commands_pristine_command.rb +73 -27
  110. data/test/rubygems/test_gem_commands_push_command.rb +76 -8
  111. data/test/rubygems/test_gem_commands_query_command.rb +239 -49
  112. data/test/rubygems/test_gem_commands_sources_command.rb +10 -43
  113. data/test/rubygems/test_gem_commands_specification_command.rb +24 -47
  114. data/test/rubygems/test_gem_commands_stale_command.rb +2 -2
  115. data/test/rubygems/test_gem_commands_uninstall_command.rb +3 -3
  116. data/test/rubygems/test_gem_commands_unpack_command.rb +16 -30
  117. data/test/rubygems/test_gem_commands_update_command.rb +149 -134
  118. data/test/rubygems/test_gem_commands_which_command.rb +4 -2
  119. data/test/rubygems/test_gem_dependency_installer.rb +68 -0
  120. data/test/rubygems/test_gem_dependency_list.rb +17 -17
  121. data/test/rubygems/test_gem_dependency_resolution_error.rb +28 -0
  122. data/test/rubygems/test_gem_doctor.rb +1 -1
  123. data/test/rubygems/test_gem_ext_builder.rb +178 -8
  124. data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -7
  125. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -10
  126. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +18 -21
  127. data/test/rubygems/test_gem_ext_rake_builder.rb +1 -3
  128. data/test/rubygems/test_gem_impossible_dependencies_error.rb +10 -6
  129. data/test/rubygems/test_gem_indexer.rb +6 -6
  130. data/test/rubygems/test_gem_installer.rb +29 -10
  131. data/test/rubygems/test_gem_local_remote_options.rb +1 -1
  132. data/test/rubygems/test_gem_package.rb +18 -0
  133. data/test/rubygems/test_gem_rdoc.rb +1 -1
  134. data/test/rubygems/test_gem_remote_fetcher.rb +1 -1
  135. data/test/rubygems/test_gem_request.rb +37 -10
  136. data/test/rubygems/test_gem_request_set.rb +271 -9
  137. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +684 -0
  138. data/test/rubygems/test_gem_request_set_lockfile.rb +849 -0
  139. data/test/rubygems/test_gem_requirement.rb +21 -0
  140. data/test/rubygems/{test_gem_dependency_resolver.rb → test_gem_resolver.rb} +231 -70
  141. data/test/rubygems/test_gem_resolver_activation_request.rb +63 -0
  142. data/test/rubygems/test_gem_resolver_api_set.rb +167 -0
  143. data/test/rubygems/test_gem_resolver_api_specification.rb +104 -0
  144. data/test/rubygems/test_gem_resolver_best_set.rb +30 -0
  145. data/test/rubygems/test_gem_resolver_conflict.rb +75 -0
  146. data/test/rubygems/test_gem_resolver_dependency_request.rb +20 -0
  147. data/test/rubygems/test_gem_resolver_git_set.rb +148 -0
  148. data/test/rubygems/test_gem_resolver_git_specification.rb +100 -0
  149. data/test/rubygems/test_gem_resolver_index_set.rb +28 -0
  150. data/test/rubygems/test_gem_resolver_index_specification.rb +89 -0
  151. data/test/rubygems/test_gem_resolver_installed_specification.rb +49 -0
  152. data/test/rubygems/test_gem_resolver_installer_set.rb +22 -0
  153. data/test/rubygems/test_gem_resolver_local_specification.rb +45 -0
  154. data/test/rubygems/test_gem_resolver_lock_set.rb +57 -0
  155. data/test/rubygems/test_gem_resolver_lock_specification.rb +87 -0
  156. data/test/rubygems/test_gem_resolver_requirement_list.rb +20 -0
  157. data/test/rubygems/test_gem_resolver_specification.rb +32 -0
  158. data/test/rubygems/test_gem_resolver_vendor_set.rb +67 -0
  159. data/test/rubygems/test_gem_resolver_vendor_specification.rb +83 -0
  160. data/test/rubygems/test_gem_server.rb +4 -4
  161. data/test/rubygems/test_gem_source.rb +54 -64
  162. data/test/rubygems/test_gem_source_git.rb +231 -0
  163. data/test/rubygems/test_gem_source_list.rb +24 -0
  164. data/test/rubygems/test_gem_source_local.rb +1 -1
  165. data/test/rubygems/test_gem_source_lock.rb +114 -0
  166. data/test/rubygems/test_gem_source_vendor.rb +27 -0
  167. data/test/rubygems/test_gem_spec_fetcher.rb +116 -61
  168. data/test/rubygems/test_gem_specification.rb +526 -94
  169. data/test/rubygems/test_gem_stub_specification.rb +123 -10
  170. data/test/rubygems/test_gem_uninstaller.rb +28 -2
  171. data/test/rubygems/test_gem_util.rb +31 -0
  172. data/test/rubygems/test_gem_validator.rb +9 -0
  173. data/util/update_bundled_ca_certificates.rb +8 -1
  174. metadata +89 -29
  175. metadata.gz.sig +2 -4
  176. data/lib/rubygems/dependency_resolver.rb +0 -254
  177. data/lib/rubygems/dependency_resolver/activation_request.rb +0 -109
  178. data/lib/rubygems/dependency_resolver/api_set.rb +0 -65
  179. data/lib/rubygems/dependency_resolver/api_specification.rb +0 -39
  180. data/lib/rubygems/dependency_resolver/composed_set.rb +0 -18
  181. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +0 -85
  182. data/lib/rubygems/dependency_resolver/index_set.rb +0 -64
  183. data/lib/rubygems/dependency_resolver/index_specification.rb +0 -60
  184. data/lib/rubygems/dependency_resolver/installed_specification.rb +0 -52
  185. data/test/rubygems/test_gem_dependency_resolver_api_specification.rb +0 -33
  186. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +0 -36
  187. data/test/rubygems/test_gem_dependency_resolver_index_set.rb +0 -53
  188. data/test/rubygems/test_gem_dependency_resolver_index_specification.rb +0 -73
  189. data/test/rubygems/test_gem_dependency_resolver_installed_specification.rb +0 -19
  190. data/test/rubygems/test_gem_dependency_resolver_installer_set.rb +0 -28
@@ -101,6 +101,24 @@ class Gem::FakeFetcher
101
101
  response
102
102
  end
103
103
 
104
+ def pretty_print q # :nodoc:
105
+ q.group 2, '[FakeFetcher', ']' do
106
+ q.breakable
107
+ q.text 'URIs:'
108
+
109
+ q.breakable
110
+ q.pp @data.keys
111
+
112
+ unless @api_endpoints.empty? then
113
+ q.breakable
114
+ q.text 'API endpoints:'
115
+
116
+ q.breakable
117
+ q.pp @api_endpoints.keys
118
+ end
119
+ end
120
+ end
121
+
104
122
  def fetch_size(path)
105
123
  path = path.to_s
106
124
  @paths << path
@@ -159,6 +177,179 @@ class Gem::RemoteFetcher
159
177
  end
160
178
  # :startdoc:
161
179
 
180
+ ##
181
+ # The SpecFetcherSetup allows easy setup of a remote source in RubyGems tests:
182
+ #
183
+ # spec_fetcher do |f|
184
+ # f.gem 'a', 1
185
+ # f.spec 'a', 2
186
+ # f.gem 'b', 1' 'a' => '~> 1.0'
187
+ # f.clear
188
+ # end
189
+ #
190
+ # The above declaration creates two gems, a-1 and b-1, with a dependency from
191
+ # b to a. The declaration creates an additional spec a-2, but no gem for it
192
+ # (so it cannot be installed).
193
+ #
194
+ # After the gems are created they are removed from Gem.dir.
195
+
196
+ class Gem::TestCase::SpecFetcherSetup
197
+
198
+ ##
199
+ # Executes a SpecFetcher setup block. Yields an instance then creates the
200
+ # gems and specifications defined in the instance.
201
+
202
+ def self.declare test, repository
203
+ setup = new test, repository
204
+
205
+ yield setup
206
+
207
+ setup.execute
208
+ end
209
+
210
+ def initialize test, repository # :nodoc:
211
+ @test = test
212
+ @repository = repository
213
+
214
+ @gems = {}
215
+ @installed = []
216
+ @operations = []
217
+ end
218
+
219
+ ##
220
+ # Removes any created gems or specifications from Gem.dir (the default
221
+ # install location).
222
+
223
+ def clear
224
+ @operations << [:clear]
225
+ end
226
+
227
+ ##
228
+ # Returns a Hash of created Specification full names and the corresponding
229
+ # Specification.
230
+
231
+ def created_specs
232
+ created = {}
233
+
234
+ @gems.keys.each do |spec|
235
+ created[spec.full_name] = spec
236
+ end
237
+
238
+ created
239
+ end
240
+
241
+ ##
242
+ # Creates any defined gems or specifications
243
+
244
+ def execute # :nodoc:
245
+ execute_operations
246
+
247
+ setup_fetcher
248
+
249
+ created_specs
250
+ end
251
+
252
+ def execute_operations # :nodoc:
253
+ @operations.each do |operation, *arguments|
254
+ case operation
255
+ when :clear then
256
+ @test.util_clear_gems
257
+ @installed.clear
258
+ when :gem then
259
+ spec, gem = @test.util_gem(*arguments, &arguments.pop)
260
+
261
+ write_spec spec
262
+
263
+ @gems[spec] = gem
264
+ @installed << spec
265
+ when :spec then
266
+ spec = @test.util_spec(*arguments, &arguments.pop)
267
+
268
+ write_spec spec
269
+
270
+ @gems[spec] = nil
271
+ @installed << spec
272
+ end
273
+ end
274
+ end
275
+
276
+ ##
277
+ # Creates a gem with +name+, +version+ and +deps+. The created gem can be
278
+ # downloaded and installed.
279
+ #
280
+ # The specification will be yielded before gem creation for customization,
281
+ # but only the block or the dependencies may be set, not both.
282
+
283
+ def gem name, version, dependencies = nil, &block
284
+ @operations << [:gem, name, version, dependencies, block]
285
+ end
286
+
287
+ ##
288
+ # Creates a legacy platform spec with the name 'pl' and version 1
289
+
290
+ def legacy_platform
291
+ spec 'pl', 1 do |s|
292
+ s.platform = Gem::Platform.new 'i386-linux'
293
+ s.instance_variable_set :@original_platform, 'i386-linux'
294
+ end
295
+ end
296
+
297
+ def setup_fetcher # :nodoc:
298
+ require 'zlib'
299
+ require 'socket'
300
+ require 'rubygems/remote_fetcher'
301
+
302
+ unless @test.fetcher then
303
+ @test.fetcher = Gem::FakeFetcher.new
304
+ Gem::RemoteFetcher.fetcher = @test.fetcher
305
+ end
306
+
307
+ Gem::Specification.reset
308
+
309
+ begin
310
+ gem_repo, @test.gem_repo = @test.gem_repo, @repository
311
+ @test.uri = URI @repository
312
+
313
+ @test.util_setup_spec_fetcher(*@gems.keys)
314
+ ensure
315
+ @test.gem_repo = gem_repo
316
+ @test.uri = URI gem_repo
317
+ end
318
+
319
+ # This works around util_setup_spec_fetcher adding all created gems to the
320
+ # installed set.
321
+ Gem::Specification.reset
322
+ Gem::Specification.add_specs(*@installed)
323
+
324
+ @gems.each do |spec, gem|
325
+ next unless gem
326
+
327
+ @test.fetcher.data["#{@repository}gems/#{spec.file_name}"] =
328
+ Gem.read_binary(gem)
329
+
330
+ FileUtils.cp gem, spec.cache_file
331
+ end
332
+ end
333
+
334
+ ##
335
+ # Creates a spec with +name+, +version+ and +deps+. The created gem can be
336
+ # downloaded and installed.
337
+ #
338
+ # The specification will be yielded before creation for customization,
339
+ # but only the block or the dependencies may be set, not both.
340
+
341
+ def spec name, version, dependencies = nil, &block
342
+ @operations << [:spec, name, version, dependencies, block]
343
+ end
344
+
345
+ def write_spec spec # :nodoc:
346
+ open spec.spec_file, 'w' do |io|
347
+ io.write spec.to_ruby_for_cache
348
+ end
349
+ end
350
+
351
+ end
352
+
162
353
  ##
163
354
  # A StringIO duck-typed class that uses Tempfile instead of String as the
164
355
  # backing store.
@@ -168,6 +359,10 @@ end
168
359
  # This class was added to flush out problems in Rubinius' IO implementation.
169
360
 
170
361
  class TempIO < Tempfile
362
+
363
+ ##
364
+ # Creates a new TempIO that will be initialized to contain +string+.
365
+
171
366
  def initialize(string = '')
172
367
  super "TempIO"
173
368
  binmode
@@ -175,6 +370,9 @@ class TempIO < Tempfile
175
370
  rewind
176
371
  end
177
372
 
373
+ ##
374
+ # The content of the TempIO as a String.
375
+
178
376
  def string
179
377
  flush
180
378
  Gem.read_binary path
@@ -247,13 +247,10 @@ class Gem::Uninstaller
247
247
  File.writable?(spec.base_dir)
248
248
 
249
249
  FileUtils.rm_rf spec.full_gem_path
250
+ FileUtils.rm_rf spec.extension_dir
250
251
 
251
- # TODO: should this be moved to spec?... I vote eww (also exists in docmgr)
252
- old_platform_name = [spec.name,
253
- spec.version,
254
- spec.original_platform].join '-'
255
-
256
- gemspec = spec.spec_file
252
+ old_platform_name = spec.original_name
253
+ gemspec = spec.spec_file
257
254
 
258
255
  unless File.exist? gemspec then
259
256
  gemspec = File.join(File.dirname(gemspec), "#{old_platform_name}.gemspec")
@@ -284,18 +281,30 @@ class Gem::Uninstaller
284
281
  full_path == spec.full_gem_path || original_path == spec.full_gem_path
285
282
  end
286
283
 
287
- def dependencies_ok?(spec)
284
+ ##
285
+ # Returns true if it is OK to remove +spec+ or this is a forced
286
+ # uninstallation.
287
+
288
+ def dependencies_ok? spec # :nodoc:
288
289
  return true if @force_ignore
289
290
 
290
291
  deplist = Gem::DependencyList.from_specs
291
292
  deplist.ok_to_remove?(spec.full_name, @check_dev)
292
293
  end
293
294
 
294
- def abort_on_dependent?
295
+ ##
296
+ # Should the uninstallation abort if a dependency will go unsatisfied?
297
+ #
298
+ # See ::new.
299
+
300
+ def abort_on_dependent? # :nodoc:
295
301
  @abort_on_dependent
296
302
  end
297
303
 
298
- def ask_if_ok(spec)
304
+ ##
305
+ # Asks if it is OK to remove +spec+. Returns true if it is OK.
306
+
307
+ def ask_if_ok spec # :nodoc:
299
308
  msg = ['']
300
309
  msg << 'You have requested to uninstall the gem:'
301
310
  msg << "\t#{spec.full_name}"
@@ -316,7 +325,10 @@ class Gem::Uninstaller
316
325
  return ask_yes_no(msg.join("\n"), false)
317
326
  end
318
327
 
319
- def formatted_program_filename(filename)
328
+ ##
329
+ # Returns the formatted version of the executable +filename+
330
+
331
+ def formatted_program_filename filename # :nodoc:
320
332
  # TODO perhaps the installer should leave a small manifest
321
333
  # of what it did for us to find rather than trying to recreate
322
334
  # it again.
@@ -1,13 +1,30 @@
1
1
  require 'cgi'
2
2
  require 'uri'
3
3
 
4
+ ##
5
+ # The UriFormatter handles URIs from user-input and escaping.
6
+ #
7
+ # uf = Gem::UriFormatter.new 'example.com'
8
+ #
9
+ # p uf.normalize #=> 'http://example.com'
10
+
4
11
  class Gem::UriFormatter
12
+
13
+ ##
14
+ # The URI to be formatted.
15
+
5
16
  attr_reader :uri
6
17
 
18
+ ##
19
+ # Creates a new URI formatter for +uri+.
20
+
7
21
  def initialize uri
8
22
  @uri = uri
9
23
  end
10
24
 
25
+ ##
26
+ # Escapes the #uri for use as a CGI parameter
27
+
11
28
  def escape
12
29
  return unless @uri
13
30
  CGI.escape @uri
@@ -20,6 +37,9 @@ class Gem::UriFormatter
20
37
  (@uri =~ /^(https?|ftp|file):/i) ? @uri : "http://#{@uri}"
21
38
  end
22
39
 
40
+ ##
41
+ # Unescapes the #uri which came from a CGI parameter
42
+
23
43
  def unescape
24
44
  return unless @uri
25
45
  CGI.unescape @uri
@@ -4,6 +4,11 @@
4
4
  # See LICENSE.txt for permissions.
5
5
  #++
6
6
 
7
+ begin
8
+ require 'io/console'
9
+ rescue LoadError
10
+ end
11
+
7
12
  ##
8
13
  # Module that defines the default UserInteraction. Any class including this
9
14
  # module will have access to the +ui+ method that returns the default UI.
@@ -66,9 +71,13 @@ module Gem::DefaultUserInteraction
66
71
  end
67
72
 
68
73
  ##
69
- # Make the default UI accessible without the "ui." prefix. Classes
70
- # including this module may use the interaction methods on the default UI
71
- # directly. Classes may also reference the ui and ui= methods.
74
+ # UserInteraction allows RubyGems to interact with the user through standard
75
+ # methods that can be replaced with more-specific UI methods for different
76
+ # displays.
77
+ #
78
+ # Since UserInteraction dispatches to a concrete UI class you may need to
79
+ # reference other classes for specific behavior such as Gem::ConsoleUI or
80
+ # Gem::SilentUI.
72
81
  #
73
82
  # Example:
74
83
  #
@@ -84,40 +93,69 @@ module Gem::UserInteraction
84
93
 
85
94
  include Gem::DefaultUserInteraction
86
95
 
87
- def alert(*args)
88
- ui.alert(*args)
96
+ ##
97
+ # Displays an alert +statement+. Asks a +question+ if given.
98
+
99
+ def alert statement, question = nil
100
+ ui.alert statement, question
89
101
  end
90
102
 
91
- def alert_error(*args)
92
- ui.alert_error(*args)
103
+ ##
104
+ # Displays an error +statement+ to the error output location. Asks a
105
+ # +question+ if given.
106
+
107
+ def alert_error statement, question = nil
108
+ ui.alert_error statement, question
93
109
  end
94
110
 
95
- def alert_warning(*args)
96
- ui.alert_warning(*args)
111
+ ##
112
+ # Displays a warning +statement+ to the warning output location. Asks a
113
+ # +question+ if given.
114
+
115
+ def alert_warning statement, question = nil
116
+ ui.alert_warning statement, question
97
117
  end
98
118
 
99
- def ask(*args)
100
- ui.ask(*args)
119
+ ##
120
+ # Asks a +question+ and returns the answer.
121
+
122
+ def ask question
123
+ ui.ask question
101
124
  end
102
125
 
103
- def ask_for_password(*args)
104
- ui.ask_for_password(*args)
126
+ ##
127
+ # Asks for a password with a +prompt+
128
+
129
+ def ask_for_password prompt
130
+ ui.ask_for_password prompt
105
131
  end
106
132
 
107
- def ask_yes_no(*args)
108
- ui.ask_yes_no(*args)
133
+ ##
134
+ # Asks a yes or no +question+. Returns true for yes, false for no.
135
+
136
+ def ask_yes_no question, default = nil
137
+ ui.ask_yes_no question, default
109
138
  end
110
139
 
111
- def choose_from_list(*args)
112
- ui.choose_from_list(*args)
140
+ ##
141
+ # Asks the user to answer +question+ with an answer from the given +list+.
142
+
143
+ def choose_from_list question, list
144
+ ui.choose_from_list question, list
113
145
  end
114
146
 
115
- def say(*args)
116
- ui.say(*args)
147
+ ##
148
+ # Displays the given +statement+ on the standard output (or equivalent).
149
+
150
+ def say statement = ''
151
+ ui.say statement
117
152
  end
118
153
 
119
- def terminate_interaction(*args)
120
- ui.terminate_interaction(*args)
154
+ ##
155
+ # Terminates the RubyGems process with the given +exit_code+
156
+
157
+ def terminate_interaction exit_code = 0
158
+ ui.terminate_interaction exit_code
121
159
  end
122
160
  end
123
161
 
@@ -126,7 +164,26 @@ end
126
164
 
127
165
  class Gem::StreamUI
128
166
 
129
- attr_reader :ins, :outs, :errs
167
+ ##
168
+ # The input stream
169
+
170
+ attr_reader :ins
171
+
172
+ ##
173
+ # The output stream
174
+
175
+ attr_reader :outs
176
+
177
+ ##
178
+ # The error stream
179
+
180
+ attr_reader :errs
181
+
182
+ ##
183
+ # Creates a new StreamUI wrapping +in_stream+ for user input, +out_stream+
184
+ # for standard output, +err_stream+ for error output. If +usetty+ is true
185
+ # then special operations (like asking for passwords) will use the TTY
186
+ # commands to disable character echo.
130
187
 
131
188
  def initialize(in_stream, out_stream, err_stream=STDERR, usetty=true)
132
189
  @ins = in_stream
@@ -135,6 +192,9 @@ class Gem::StreamUI
135
192
  @usetty = usetty
136
193
  end
137
194
 
195
+ ##
196
+ # Returns true if TTY methods should be used on this StreamUI.
197
+
138
198
  def tty?
139
199
  if RUBY_VERSION < '1.9.3' and RUBY_PLATFORM =~ /mingw|mswin/ then
140
200
  @usetty
@@ -228,41 +288,27 @@ class Gem::StreamUI
228
288
  result
229
289
  end
230
290
 
231
- if RUBY_VERSION > '1.9.2' then
232
- ##
233
- # Ask for a password. Does not echo response to terminal.
234
-
235
- def ask_for_password(question)
236
- return nil if not tty?
237
-
238
- require 'io/console'
239
-
240
- @outs.print(question + " ")
241
- @outs.flush
291
+ ##
292
+ # Ask for a password. Does not echo response to terminal.
242
293
 
243
- password = @ins.noecho {@ins.gets}
244
- password.chomp! if password
245
- password
246
- end
247
- else
248
- ##
249
- # Ask for a password. Does not echo response to terminal.
294
+ def ask_for_password(question)
295
+ return nil if not tty?
250
296
 
251
- def ask_for_password(question)
252
- return nil if not tty?
297
+ @outs.print(question, " ")
298
+ @outs.flush
253
299
 
254
- @outs.print(question + " ")
255
- @outs.flush
300
+ password = _gets_noecho
301
+ @outs.puts
302
+ password.chomp! if password
303
+ password
304
+ end
256
305
 
257
- Gem.win_platform? ? ask_for_password_on_windows : ask_for_password_on_unix
306
+ if IO.method_defined?(:noecho) then
307
+ def _gets_noecho
308
+ @ins.noecho {@ins.gets}
258
309
  end
259
-
260
- ##
261
- # Asks for a password that works on windows. Ripped from the Heroku gem.
262
-
263
- def ask_for_password_on_windows
264
- return nil if not tty?
265
-
310
+ elsif Gem.win_platform?
311
+ def _gets_noecho
266
312
  require "Win32API"
267
313
  char = nil
268
314
  password = ''
@@ -275,22 +321,16 @@ class Gem::StreamUI
275
321
  password << char.chr
276
322
  end
277
323
  end
278
-
279
- puts
280
324
  password
281
325
  end
282
-
283
- ##
284
- # Asks for a password that works on unix
285
-
286
- def ask_for_password_on_unix
287
- return nil if not tty?
288
-
326
+ else
327
+ def _gets_noecho
289
328
  system "stty -echo"
290
- password = @ins.gets
291
- password.chomp! if password
292
- system "stty echo"
293
- password
329
+ begin
330
+ @ins.gets
331
+ ensure
332
+ system "stty echo"
333
+ end
294
334
  end
295
335
  end
296
336
 
@@ -310,8 +350,7 @@ class Gem::StreamUI
310
350
  end
311
351
 
312
352
  ##
313
- # Display a warning in a location expected to get error messages. Will
314
- # ask +question+ if it is not nil.
353
+ # Display a warning on stderr. Will ask +question+ if it is not nil.
315
354
 
316
355
  def alert_warning(statement, question=nil)
317
356
  @errs.puts "WARNING: #{statement}"
@@ -364,14 +403,29 @@ class Gem::StreamUI
364
403
  # An absolutely silent progress reporter.
365
404
 
366
405
  class SilentProgressReporter
406
+
407
+ ##
408
+ # The count of items is never updated for the silent progress reporter.
409
+
367
410
  attr_reader :count
368
411
 
412
+ ##
413
+ # Creates a silent progress reporter that ignores all input arguments.
414
+
369
415
  def initialize(out_stream, size, initial_message, terminal_message = nil)
370
416
  end
371
417
 
418
+ ##
419
+ # Does not print +message+ when updated as this object has taken a vow of
420
+ # silence.
421
+
372
422
  def updated(message)
373
423
  end
374
424
 
425
+ ##
426
+ # Does not print anything when complete as this object has taken a vow of
427
+ # silence.
428
+
375
429
  def done
376
430
  end
377
431
  end
@@ -383,8 +437,16 @@ class Gem::StreamUI
383
437
 
384
438
  include Gem::DefaultUserInteraction
385
439
 
440
+ ##
441
+ # The number of progress items counted so far.
442
+
386
443
  attr_reader :count
387
444
 
445
+ ##
446
+ # Creates a new progress reporter that will write to +out_stream+ for
447
+ # +size+ items. Shows the given +initial_message+ when progress starts
448
+ # and the +terminal_message+ when it is complete.
449
+
388
450
  def initialize(out_stream, size, initial_message,
389
451
  terminal_message = "complete")
390
452
  @out = out_stream
@@ -420,8 +482,16 @@ class Gem::StreamUI
420
482
 
421
483
  include Gem::DefaultUserInteraction
422
484
 
485
+ ##
486
+ # The number of progress items counted so far.
487
+
423
488
  attr_reader :count
424
489
 
490
+ ##
491
+ # Creates a new progress reporter that will write to +out_stream+ for
492
+ # +size+ items. Shows the given +initial_message+ when progress starts
493
+ # and the +terminal_message+ when it is complete.
494
+
425
495
  def initialize(out_stream, size, initial_message,
426
496
  terminal_message = 'complete')
427
497
  @out = out_stream
@@ -468,15 +538,30 @@ class Gem::StreamUI
468
538
  # An absolutely silent download reporter.
469
539
 
470
540
  class SilentDownloadReporter
541
+
542
+ ##
543
+ # The silent download reporter ignores all arguments
544
+
471
545
  def initialize(out_stream, *args)
472
546
  end
473
547
 
548
+ ##
549
+ # The silent download reporter does not display +filename+ or care about
550
+ # +filesize+ because it is silent.
551
+
474
552
  def fetch(filename, filesize)
475
553
  end
476
554
 
555
+ ##
556
+ # Nothing can update the silent download reporter.
557
+
477
558
  def update(current)
478
559
  end
479
560
 
561
+ ##
562
+ # The silent download reporter won't tell you when the download is done.
563
+ # Because it is silent.
564
+
480
565
  def done
481
566
  end
482
567
  end
@@ -485,13 +570,35 @@ class Gem::StreamUI
485
570
  # A progress reporter that prints out messages about the current progress.
486
571
 
487
572
  class VerboseDownloadReporter
488
- attr_reader :file_name, :total_bytes, :progress
573
+
574
+ ##
575
+ # The current file name being displayed
576
+
577
+ attr_reader :file_name
578
+
579
+ ##
580
+ # The total bytes in the file
581
+
582
+ attr_reader :total_bytes
583
+
584
+ ##
585
+ # The current progress (0 to 100)
586
+
587
+ attr_reader :progress
588
+
589
+ ##
590
+ # Creates a new verbose download reporter that will display on
591
+ # +out_stream+. The other arguments are ignored.
489
592
 
490
593
  def initialize(out_stream, *args)
491
594
  @out = out_stream
492
595
  @progress = 0
493
596
  end
494
597
 
598
+ ##
599
+ # Tells the download reporter that the +file_name+ is being fetched and
600
+ # contains +total_bytes+.
601
+
495
602
  def fetch(file_name, total_bytes)
496
603
  @file_name = file_name
497
604
  @total_bytes = total_bytes.to_i
@@ -500,6 +607,9 @@ class Gem::StreamUI
500
607
  update_display(false)
501
608
  end
502
609
 
610
+ ##
611
+ # Updates the verbose download reporter for the given number of +bytes+.
612
+
503
613
  def update(bytes)
504
614
  new_progress = if @units == 'B' then
505
615
  bytes
@@ -513,6 +623,9 @@ class Gem::StreamUI
513
623
  update_display
514
624
  end
515
625
 
626
+ ##
627
+ # Indicates the download is complete.
628
+
516
629
  def done
517
630
  @progress = 100 if @units == '%'
518
631
  update_display(true, true)
@@ -520,7 +633,7 @@ class Gem::StreamUI
520
633
 
521
634
  private
522
635
 
523
- def update_display(show_progress = true, new_line = false)
636
+ def update_display(show_progress = true, new_line = false) # :nodoc:
524
637
  return unless @out.tty?
525
638
 
526
639
  if show_progress then
@@ -538,6 +651,11 @@ end
538
651
  # STDOUT, and STDERR.
539
652
 
540
653
  class Gem::ConsoleUI < Gem::StreamUI
654
+
655
+ ##
656
+ # The Console UI has no arguments as it defaults to reading input from
657
+ # stdin, output to stdout and warnings or errors to stderr.
658
+
541
659
  def initialize
542
660
  super STDIN, STDOUT, STDERR, true
543
661
  end
@@ -547,6 +665,10 @@ end
547
665
  # SilentUI is a UI choice that is absolutely silent.
548
666
 
549
667
  class Gem::SilentUI < Gem::StreamUI
668
+
669
+ ##
670
+ # The SilentUI has no arguments as it does not use any stream.
671
+
550
672
  def initialize
551
673
  reader, writer = nil, nil
552
674
 
@@ -561,11 +683,11 @@ class Gem::SilentUI < Gem::StreamUI
561
683
  super reader, writer, writer, false
562
684
  end
563
685
 
564
- def download_reporter(*args)
686
+ def download_reporter(*args) # :nodoc:
565
687
  SilentDownloadReporter.new(@outs, *args)
566
688
  end
567
689
 
568
- def progress_reporter(*args)
690
+ def progress_reporter(*args) # :nodoc:
569
691
  SilentProgressReporter.new(@outs, *args)
570
692
  end
571
693
  end