rubygems-update 2.4.8 → 2.5.0

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 (125) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CODE_OF_CONDUCT.md +40 -0
  5. data/CVE-2015-3900.txt +40 -0
  6. data/History.txt +173 -2
  7. data/Manifest.txt +14 -1
  8. data/Rakefile +36 -1
  9. data/lib/rubygems.rb +32 -14
  10. data/lib/rubygems/basic_specification.rb +31 -9
  11. data/lib/rubygems/commands/dependency_command.rb +25 -15
  12. data/lib/rubygems/commands/environment_command.rb +2 -0
  13. data/lib/rubygems/commands/help_command.rb +0 -10
  14. data/lib/rubygems/commands/install_command.rb +1 -1
  15. data/lib/rubygems/commands/list_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +11 -1
  17. data/lib/rubygems/commands/query_command.rb +1 -1
  18. data/lib/rubygems/commands/sources_command.rb +1 -1
  19. data/lib/rubygems/commands/update_command.rb +2 -2
  20. data/lib/rubygems/config_file.rb +4 -4
  21. data/lib/rubygems/core_ext/kernel_require.rb +2 -2
  22. data/lib/rubygems/dependency.rb +9 -6
  23. data/lib/rubygems/dependency_list.rb +3 -0
  24. data/lib/rubygems/ext/builder.rb +2 -0
  25. data/lib/rubygems/ext/ext_conf_builder.rb +6 -1
  26. data/lib/rubygems/indexer.rb +26 -91
  27. data/lib/rubygems/installer.rb +58 -26
  28. data/lib/rubygems/installer_test_case.rb +2 -2
  29. data/lib/rubygems/package.rb +18 -6
  30. data/lib/rubygems/package/old.rb +2 -2
  31. data/lib/rubygems/package/tar_reader/entry.rb +7 -1
  32. data/lib/rubygems/package/tar_test_case.rb +12 -3
  33. data/lib/rubygems/package/tar_writer.rb +19 -1
  34. data/lib/rubygems/platform.rb +3 -2
  35. data/lib/rubygems/rdoc.rb +1 -2
  36. data/lib/rubygems/remote_fetcher.rb +25 -6
  37. data/lib/rubygems/request/connection_pools.rb +8 -4
  38. data/lib/rubygems/request_set.rb +3 -4
  39. data/lib/rubygems/request_set/gem_dependency_api.rb +2 -2
  40. data/lib/rubygems/request_set/lockfile.rb +1 -1
  41. data/lib/rubygems/request_set/lockfile/parser.rb +54 -43
  42. data/lib/rubygems/request_set/lockfile/tokenizer.rb +16 -13
  43. data/lib/rubygems/resolver.rb +47 -242
  44. data/lib/rubygems/resolver/activation_request.rb +2 -1
  45. data/lib/rubygems/resolver/conflict.rb +0 -1
  46. data/lib/rubygems/resolver/dependency_request.rb +4 -1
  47. data/lib/rubygems/resolver/git_specification.rb +1 -2
  48. data/lib/rubygems/resolver/molinillo.rb +1 -0
  49. data/lib/rubygems/resolver/molinillo/lib/molinillo.rb +5 -0
  50. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +266 -0
  51. data/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb +69 -0
  52. data/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +3 -0
  53. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb +99 -0
  54. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb +63 -0
  55. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +430 -0
  56. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb +43 -0
  57. data/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb +51 -0
  58. data/lib/rubygems/resolver/specification.rb +1 -1
  59. data/lib/rubygems/specification.rb +256 -86
  60. data/lib/rubygems/stub_specification.rb +37 -29
  61. data/lib/rubygems/test_case.rb +65 -28
  62. data/lib/rubygems/test_utilities.rb +18 -18
  63. data/lib/rubygems/text.rb +0 -2
  64. data/lib/rubygems/uninstaller.rb +1 -1
  65. data/lib/rubygems/util.rb +4 -4
  66. data/lib/rubygems/util/licenses.rb +309 -0
  67. data/lib/rubygems/util/list.rb +9 -21
  68. data/lib/rubygems/version.rb +24 -14
  69. data/test/rubygems/simple_gem.rb +1 -1
  70. data/test/rubygems/test_config.rb +10 -1
  71. data/test/rubygems/test_gem.rb +58 -11
  72. data/test/rubygems/test_gem_available_set.rb +2 -1
  73. data/test/rubygems/test_gem_commands_cleanup_command.rb +6 -5
  74. data/test/rubygems/test_gem_commands_dependency_command.rb +9 -1
  75. data/test/rubygems/test_gem_commands_install_command.rb +17 -28
  76. data/test/rubygems/test_gem_commands_mirror.rb +0 -13
  77. data/test/rubygems/test_gem_commands_outdated_command.rb +2 -3
  78. data/test/rubygems/test_gem_commands_pristine_command.rb +33 -5
  79. data/test/rubygems/test_gem_commands_query_command.rb +123 -158
  80. data/test/rubygems/test_gem_commands_server_command.rb +2 -2
  81. data/test/rubygems/test_gem_commands_specification_command.rb +4 -4
  82. data/test/rubygems/test_gem_commands_stale_command.rb +2 -0
  83. data/test/rubygems/test_gem_commands_uninstall_command.rb +5 -4
  84. data/test/rubygems/test_gem_commands_unpack_command.rb +4 -6
  85. data/test/rubygems/test_gem_commands_update_command.rb +22 -52
  86. data/test/rubygems/test_gem_commands_which_command.rb +1 -0
  87. data/test/rubygems/test_gem_config_file.rb +1 -1
  88. data/test/rubygems/test_gem_dependency.rb +7 -3
  89. data/test/rubygems/test_gem_dependency_installer.rb +5 -5
  90. data/test/rubygems/test_gem_doctor.rb +1 -1
  91. data/test/rubygems/test_gem_ext_builder.rb +2 -0
  92. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -4
  93. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +25 -21
  94. data/test/rubygems/test_gem_indexer.rb +4 -4
  95. data/test/rubygems/test_gem_install_update_options.rb +2 -2
  96. data/test/rubygems/test_gem_installer.rb +32 -26
  97. data/test/rubygems/test_gem_package.rb +46 -1
  98. data/test/rubygems/test_gem_package_tar_reader_entry.rb +8 -1
  99. data/test/rubygems/test_gem_package_tar_writer.rb +10 -1
  100. data/test/rubygems/test_gem_package_task.rb +5 -2
  101. data/test/rubygems/test_gem_platform.rb +11 -0
  102. data/test/rubygems/test_gem_remote_fetcher.rb +64 -3
  103. data/test/rubygems/test_gem_request.rb +1 -1
  104. data/test/rubygems/test_gem_request_connection_pools.rb +10 -1
  105. data/test/rubygems/test_gem_request_set.rb +5 -8
  106. data/test/rubygems/test_gem_request_set_lockfile.rb +2 -4
  107. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +1 -1
  108. data/test/rubygems/test_gem_resolver.rb +12 -31
  109. data/test/rubygems/test_gem_resolver_git_specification.rb +1 -0
  110. data/test/rubygems/test_gem_resolver_installer_set.rb +7 -11
  111. data/test/rubygems/test_gem_resolver_lock_specification.rb +3 -2
  112. data/test/rubygems/test_gem_security_trust_dir.rb +2 -0
  113. data/test/rubygems/test_gem_server.rb +4 -0
  114. data/test/rubygems/test_gem_specification.rb +344 -61
  115. data/test/rubygems/test_gem_stream_ui.rb +6 -6
  116. data/test/rubygems/test_gem_stub_specification.rb +21 -6
  117. data/test/rubygems/test_gem_text.rb +2 -0
  118. data/test/rubygems/test_gem_uninstaller.rb +2 -1
  119. data/test/rubygems/test_gem_util.rb +8 -0
  120. data/test/rubygems/test_require.rb +156 -125
  121. data/util/generate_spdx_license_list.rb +21 -0
  122. data/util/update_bundled_ca_certificates.rb +2 -1
  123. metadata +42 -6
  124. metadata.gz.sig +0 -0
  125. data/lib/rubygems/util/stringio.rb +0 -34
@@ -15,9 +15,8 @@ class TestGemCommandsOutdatedCommand < Gem::TestCase
15
15
 
16
16
  def test_execute
17
17
  spec_fetcher do |fetcher|
18
- fetcher.spec 'foo', '1.0'
19
- fetcher.spec 'foo', '2.0'
20
- fetcher.clear
18
+ fetcher.download 'foo', '1.0'
19
+ fetcher.download 'foo', '2.0'
21
20
  fetcher.gem 'foo', '0.1'
22
21
  fetcher.gem 'foo', '0.2'
23
22
  end
@@ -5,6 +5,8 @@ class TestGemCommandsPristineCommand < Gem::TestCase
5
5
 
6
6
  def setup
7
7
  super
8
+ common_installer_setup
9
+
8
10
  @cmd = Gem::Commands::PristineCommand.new
9
11
  end
10
12
 
@@ -103,10 +105,12 @@ class TestGemCommandsPristineCommand < Gem::TestCase
103
105
 
104
106
  assert_path_exists gem_exec
105
107
 
108
+ ruby_exec = sprintf Gem.default_exec_format, 'ruby'
109
+
106
110
  if win_platform?
107
- assert_match %r%\A#!\s*ruby%, File.read(gem_exec)
111
+ assert_match %r%\A#!\s*#{ruby_exec}%, File.read(gem_exec)
108
112
  else
109
- assert_match %r%\A#!\s*/usr/bin/env ruby%, File.read(gem_exec)
113
+ assert_match %r%\A#!\s*/usr/bin/env #{ruby_exec}%, File.read(gem_exec)
110
114
  end
111
115
  end
112
116
 
@@ -151,10 +155,11 @@ class TestGemCommandsPristineCommand < Gem::TestCase
151
155
 
152
156
  ext_path = File.join @tempdir, 'ext', 'a', 'extconf.rb'
153
157
  write_file ext_path do |io|
154
- io.write '# extconf.rb'
158
+ io.write "# extconf.rb\nrequire 'mkmf'; create_makefile 'a'"
155
159
  end
156
160
 
157
161
  util_build_gem a
162
+ install_gem a
158
163
 
159
164
  @cmd.options[:args] = %w[a]
160
165
  @cmd.options[:extensions] = false
@@ -225,6 +230,28 @@ class TestGemCommandsPristineCommand < Gem::TestCase
225
230
  assert_empty out, out.inspect
226
231
  end
227
232
 
233
+ def test_skip
234
+ a = util_spec 'a'
235
+ b = util_spec 'b'
236
+
237
+ install_gem a
238
+ install_gem b
239
+
240
+ @cmd.options[:args] = %w[a b]
241
+ @cmd.options[:skip] = 'a'
242
+
243
+ use_ui @ui do
244
+ @cmd.execute
245
+ end
246
+
247
+ out = @ui.output.split "\n"
248
+
249
+ assert_equal "Restoring gems to pristine condition...", out.shift
250
+ assert_equal "Skipped #{a.full_name}, it was given through options", out.shift
251
+ assert_equal "Restored #{b.full_name}", out.shift
252
+ assert_empty out, out.inspect
253
+ end
254
+
228
255
  def test_execute_many_multi_repo
229
256
  a = util_spec 'a'
230
257
  install_gem a
@@ -381,7 +408,7 @@ class TestGemCommandsPristineCommand < Gem::TestCase
381
408
  end
382
409
 
383
410
  def test_execute_unknown_gem_at_remote_source
384
- util_spec 'a'
411
+ install_specs util_spec 'a'
385
412
 
386
413
  @cmd.options[:args] = %w[a]
387
414
 
@@ -420,9 +447,10 @@ class TestGemCommandsPristineCommand < Gem::TestCase
420
447
  def test_execute_bundled_gem_on_old_rubies
421
448
  util_set_RUBY_VERSION '1.9.3', 551
422
449
 
423
- util_spec 'bigdecimal', '1.1.0' do |s|
450
+ spec = util_spec 'bigdecimal', '1.1.0' do |s|
424
451
  s.summary = "This bigdecimal is bundled with Ruby"
425
452
  end
453
+ install_specs spec
426
454
 
427
455
  @cmd.options[:args] = %w[bigdecimal]
428
456
 
@@ -1,23 +1,22 @@
1
1
  require 'rubygems/test_case'
2
2
  require 'rubygems/commands/query_command'
3
3
 
4
- class TestGemCommandsQueryCommand < Gem::TestCase
5
-
4
+ module TestGemCommandsQueryCommandSetup
6
5
  def setup
7
6
  super
8
7
 
9
8
  @cmd = Gem::Commands::QueryCommand.new
10
9
 
11
- @specs = spec_fetcher do |fetcher|
12
- fetcher.spec 'a', 1
13
- fetcher.spec 'a', 2
14
- fetcher.spec 'a', '3.a'
15
- end
10
+ @specs = add_gems_to_fetcher
16
11
 
17
12
  @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
18
13
  raise Gem::RemoteFetcher::FetchError
19
14
  end
20
15
  end
16
+ end
17
+
18
+ class TestGemCommandsQueryCommandWithInstalledGems < Gem::TestCase
19
+ include TestGemCommandsQueryCommandSetup
21
20
 
22
21
  def test_execute
23
22
  spec_fetcher do |fetcher|
@@ -42,37 +41,6 @@ pl (1 i386-linux)
42
41
  assert_equal '', @ui.error
43
42
  end
44
43
 
45
- def test_execute_platform
46
- spec_fetcher do |fetcher|
47
- fetcher.clear
48
-
49
- fetcher.spec 'a', 1
50
- fetcher.spec 'a', 1 do |s|
51
- s.platform = 'x86-linux'
52
- end
53
-
54
- fetcher.spec 'a', 2 do |s|
55
- s.platform = 'universal-darwin'
56
- end
57
- end
58
-
59
- @cmd.handle_options %w[-r -a]
60
-
61
- use_ui @ui do
62
- @cmd.execute
63
- end
64
-
65
- expected = <<-EOF
66
-
67
- *** REMOTE GEMS ***
68
-
69
- a (2 universal-darwin, 1 ruby x86-linux)
70
- EOF
71
-
72
- assert_equal expected, @ui.output
73
- assert_equal '', @ui.error
74
- end
75
-
76
44
  def test_execute_all
77
45
  spec_fetcher do |fetcher|
78
46
  fetcher.legacy_platform
@@ -147,56 +115,6 @@ a (2)
147
115
  This is a lot of text. This is a lot of text. This is a lot of text.
148
116
  This is a lot of text.
149
117
 
150
- pl (1)
151
- Platform: i386-linux
152
- Author: A User
153
- Homepage: http://example.com
154
-
155
- this is a summary
156
- EOF
157
-
158
- assert_equal expected, @ui.output
159
- assert_equal '', @ui.error
160
- end
161
-
162
- def test_execute_details_platform
163
- spec_fetcher do |fetcher|
164
- fetcher.clear
165
-
166
- fetcher.spec 'a', 1 do |s|
167
- s.platform = 'x86-linux'
168
- end
169
-
170
- fetcher.spec 'a', 2 do |s|
171
- s.summary = 'This is a lot of text. ' * 4
172
- s.authors = ['Abraham Lincoln', 'Hirohito']
173
- s.homepage = 'http://a.example.com/'
174
- s.platform = 'universal-darwin'
175
- end
176
-
177
- fetcher.legacy_platform
178
- end
179
-
180
- @cmd.handle_options %w[-r -d]
181
-
182
- use_ui @ui do
183
- @cmd.execute
184
- end
185
-
186
- expected = <<-EOF
187
-
188
- *** REMOTE GEMS ***
189
-
190
- a (2, 1)
191
- Platforms:
192
- 1: x86-linux
193
- 2: universal-darwin
194
- Authors: Abraham Lincoln, Hirohito
195
- Homepage: http://a.example.com/
196
-
197
- This is a lot of text. This is a lot of text. This is a lot of text.
198
- This is a lot of text.
199
-
200
118
  pl (1)
201
119
  Platform: i386-linux
202
120
  Author: A User
@@ -526,67 +444,100 @@ pl (1 i386-linux)
526
444
  assert_equal '', @ui.error
527
445
  end
528
446
 
529
- def test_execute_local_details
447
+ def test_make_entry
448
+ a_2_name = @specs['a-2'].original_name
449
+
450
+ @fetcher.data.delete \
451
+ "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz"
452
+
453
+ a2 = @specs['a-2']
454
+ entry_tuples = [
455
+ [Gem::NameTuple.new(a2.name, a2.version, a2.platform),
456
+ Gem.sources.first],
457
+ ]
458
+
459
+ platforms = { a2.version => [a2.platform] }
460
+
461
+ entry = @cmd.send :make_entry, entry_tuples, platforms
462
+
463
+ assert_equal 'a (2)', entry
464
+ end
465
+
466
+ # Test for multiple args handling!
467
+ def test_execute_multiple_args
530
468
  spec_fetcher do |fetcher|
531
- fetcher.clear
469
+ fetcher.legacy_platform
470
+ end
471
+
472
+ @cmd.handle_options %w[a pl]
473
+
474
+ use_ui @ui do
475
+ @cmd.execute
476
+ end
532
477
 
478
+ assert_match %r%^a %, @ui.output
479
+ assert_match %r%^pl %, @ui.output
480
+ assert_equal '', @ui.error
481
+ end
482
+
483
+ def test_show_gems
484
+ @cmd.options[:name] = //
485
+ @cmd.options[:domain] = :remote
486
+
487
+ use_ui @ui do
488
+ @cmd.send :show_gems, /a/i, false
489
+ end
490
+
491
+ assert_match %r%^a %, @ui.output
492
+ refute_match %r%^pl %, @ui.output
493
+ assert_empty @ui.error
494
+ end
495
+
496
+ private
497
+
498
+ def add_gems_to_fetcher
499
+ spec_fetcher do |fetcher|
500
+ fetcher.spec 'a', 1
501
+ fetcher.spec 'a', 2
502
+ fetcher.spec 'a', '3.a'
503
+ end
504
+ end
505
+ end
506
+
507
+ class TestGemCommandsQueryCommandWithoutInstalledGems < Gem::TestCase
508
+ include TestGemCommandsQueryCommandSetup
509
+
510
+ def test_execute_platform
511
+ spec_fetcher do |fetcher|
512
+ fetcher.spec 'a', 1
533
513
  fetcher.spec 'a', 1 do |s|
534
514
  s.platform = 'x86-linux'
535
515
  end
536
516
 
537
517
  fetcher.spec 'a', 2 do |s|
538
- s.summary = 'This is a lot of text. ' * 4
539
- s.authors = ['Abraham Lincoln', 'Hirohito']
540
- s.homepage = 'http://a.example.com/'
541
518
  s.platform = 'universal-darwin'
542
519
  end
543
-
544
- fetcher.legacy_platform
545
520
  end
546
521
 
547
- @cmd.handle_options %w[-l -d]
522
+ @cmd.handle_options %w[-r -a]
548
523
 
549
524
  use_ui @ui do
550
525
  @cmd.execute
551
526
  end
552
527
 
553
- str = @ui.output
554
-
555
- str.gsub!(/\(\d\): [^\n]*/, "-")
556
- str.gsub!(/at: [^\n]*/, "at: -")
557
-
558
528
  expected = <<-EOF
559
529
 
560
- *** LOCAL GEMS ***
561
-
562
- a (2, 1)
563
- Platforms:
564
- 1: x86-linux
565
- 2: universal-darwin
566
- Authors: Abraham Lincoln, Hirohito
567
- Homepage: http://a.example.com/
568
- Installed at -
569
- -
570
-
571
- This is a lot of text. This is a lot of text. This is a lot of text.
572
- This is a lot of text.
573
-
574
- pl (1)
575
- Platform: i386-linux
576
- Author: A User
577
- Homepage: http://example.com
578
- Installed at: -
530
+ *** REMOTE GEMS ***
579
531
 
580
- this is a summary
532
+ a (2 universal-darwin, 1 ruby x86-linux)
581
533
  EOF
582
534
 
583
535
  assert_equal expected, @ui.output
536
+ assert_equal '', @ui.error
584
537
  end
585
538
 
586
539
  def test_execute_default_details
587
540
  spec_fetcher do |fetcher|
588
- fetcher.clear
589
-
590
541
  fetcher.spec 'a', 2
591
542
  end
592
543
 
@@ -615,54 +566,68 @@ a (2, 1)
615
566
  assert_equal expected, @ui.output
616
567
  end
617
568
 
618
- def test_make_entry
619
- a_2_name = @specs['a-2'].original_name
620
-
621
- @fetcher.data.delete \
622
- "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz"
623
-
624
- a2 = @specs['a-2']
625
- entry_tuples = [
626
- [Gem::NameTuple.new(a2.name, a2.version, a2.platform),
627
- Gem.sources.first],
628
- ]
629
-
630
- platforms = { a2.version => [a2.platform] }
631
-
632
- entry = @cmd.send :make_entry, entry_tuples, platforms
569
+ def test_execute_local_details
570
+ spec_fetcher do |fetcher|
571
+ fetcher.spec 'a', 1 do |s|
572
+ s.platform = 'x86-linux'
573
+ end
633
574
 
634
- assert_equal 'a (2)', entry
635
- end
575
+ fetcher.spec 'a', 2 do |s|
576
+ s.summary = 'This is a lot of text. ' * 4
577
+ s.authors = ['Abraham Lincoln', 'Hirohito']
578
+ s.homepage = 'http://a.example.com/'
579
+ s.platform = 'universal-darwin'
580
+ end
636
581
 
637
- # Test for multiple args handling!
638
- def test_execute_multiple_args
639
- spec_fetcher do |fetcher|
640
582
  fetcher.legacy_platform
641
583
  end
642
584
 
643
- @cmd.handle_options %w[a pl]
585
+ @cmd.handle_options %w[-l -d]
644
586
 
645
587
  use_ui @ui do
646
588
  @cmd.execute
647
589
  end
648
590
 
649
- assert_match %r%^a %, @ui.output
650
- assert_match %r%^pl %, @ui.output
651
- assert_equal '', @ui.error
652
- end
591
+ str = @ui.output
653
592
 
654
- def test_show_gems
655
- @cmd.options[:name] = //
656
- @cmd.options[:domain] = :remote
593
+ str.gsub!(/\(\d\): [^\n]*/, "-")
594
+ str.gsub!(/at: [^\n]*/, "at: -")
657
595
 
658
- use_ui @ui do
659
- @cmd.send :show_gems, /a/i, false
660
- end
596
+ expected = <<-EOF
661
597
 
662
- assert_match %r%^a %, @ui.output
663
- refute_match %r%^pl %, @ui.output
664
- assert_empty @ui.error
598
+ *** LOCAL GEMS ***
599
+
600
+ a (2, 1)
601
+ Platforms:
602
+ 1: x86-linux
603
+ 2: universal-darwin
604
+ Authors: Abraham Lincoln, Hirohito
605
+ Homepage: http://a.example.com/
606
+ Installed at -
607
+ -
608
+
609
+ This is a lot of text. This is a lot of text. This is a lot of text.
610
+ This is a lot of text.
611
+
612
+ pl (1)
613
+ Platform: i386-linux
614
+ Author: A User
615
+ Homepage: http://example.com
616
+ Installed at: -
617
+
618
+ this is a summary
619
+ EOF
620
+
621
+ assert_equal expected, @ui.output
665
622
  end
666
623
 
667
- end
624
+ private
668
625
 
626
+ def add_gems_to_fetcher
627
+ spec_fetcher do |fetcher|
628
+ fetcher.download 'a', 1
629
+ fetcher.download 'a', 2
630
+ fetcher.download 'a', '3.a'
631
+ end
632
+ end
633
+ end