rubygems-update 2.0.0.preview2.2 → 2.0.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.

data.tar.gz.sig CHANGED
Binary file
data/History.txt CHANGED
@@ -1,10 +1,10 @@
1
1
  # coding: UTF-8
2
2
 
3
- === 2.0.0.preview2.2 / 2012-12-14
3
+ === 2.0.0.rc.1 / 2013-01-08
4
4
 
5
5
  As a preview release, please file bugs for any problems you have with RubyGems
6
- at https://github.com/rubygems/rubygems/issues. To update to preview releases
7
- use gem update --system=2.0.0.preview2.2
6
+ at https://github.com/rubygems/rubygems/issues. To update to this preview
7
+ release use gem update --system=2.0.0.preview3
8
8
 
9
9
  RubyGems 2.0 includes several new features and many breaking changes. Some of
10
10
  these changes will cause existing software to break. These changes are a
@@ -14,8 +14,23 @@ maintainable and improve APIs for RubyGems users.
14
14
  If you are using bundler be sure to install version 1.3.0.pre. Older versions
15
15
  of bundler will not work with RubyGems 2.0.
16
16
 
17
+ * Minor enhancements:
18
+ * This release of RubyGems can push gems to rubygems.org. Ordinarily
19
+ prerelease versions of RubyGems cannot push gems.
20
+ * Added `gem check --doctor` to clean up after failed uninstallation. Bug
21
+ #419 by Erik Hollensbe
22
+
23
+ * Bug fixes:
24
+ * Fixed exception raised when attempting to push gems to rubygems.org. Bug
25
+ #418 by André Arko
26
+ * Gem installation will fail if RubyGems cannot load the specification from
27
+ the gem. Bug #419 by Erik Hollensbe
28
+
29
+ === 2.0.0.preview2.2 / 2012-12-14
30
+
17
31
  * Minor enhancements:
18
32
  * Added a cmake builder. Pull request #265 by Allan Espinosa.
33
+ * Removed rubyforge page from gem list output
19
34
 
20
35
  * Bug fixes:
21
36
  * Restored RubyGems 1.8 packaging behavior of omitting directories. Bug
data/Manifest.txt CHANGED
@@ -56,6 +56,7 @@ lib/rubygems/dependency_installer.rb
56
56
  lib/rubygems/dependency_list.rb
57
57
  lib/rubygems/dependency_resolver.rb
58
58
  lib/rubygems/deprecate.rb
59
+ lib/rubygems/doctor.rb
59
60
  lib/rubygems/errors.rb
60
61
  lib/rubygems/exceptions.rb
61
62
  lib/rubygems/ext.rb
@@ -202,6 +203,7 @@ test/rubygems/test_gem_dependency.rb
202
203
  test/rubygems/test_gem_dependency_installer.rb
203
204
  test/rubygems/test_gem_dependency_list.rb
204
205
  test/rubygems/test_gem_dependency_resolver.rb
206
+ test/rubygems/test_gem_doctor.rb
205
207
  test/rubygems/test_gem_ext_cmake_builder.rb
206
208
  test/rubygems/test_gem_ext_configure_builder.rb
207
209
  test/rubygems/test_gem_ext_ext_conf_builder.rb
data/lib/rubygems.rb CHANGED
@@ -98,7 +98,7 @@
98
98
  require 'rbconfig'
99
99
 
100
100
  module Gem
101
- VERSION = '2.0.0.preview2.2'
101
+ VERSION = '2.0.0.rc.1'
102
102
  end
103
103
 
104
104
  # Must be first since it unloads the prelude from 1.9.2
@@ -123,7 +123,22 @@ module Gem
123
123
  /wince/i,
124
124
  ]
125
125
 
126
- GEM_DEP_FILES = %w!gem.deps.rb Gemfile Isolate!
126
+ GEM_DEP_FILES = %w[
127
+ gem.deps.rb
128
+ Gemfile
129
+ Isolate
130
+ ]
131
+
132
+ ##
133
+ # Subdirectories in a gem repository
134
+
135
+ REPOSITORY_SUBDIRECTORIES = %w[
136
+ build_info
137
+ cache
138
+ doc
139
+ gems
140
+ specifications
141
+ ]
127
142
 
128
143
  @@win_platform = nil
129
144
 
@@ -388,7 +403,7 @@ module Gem
388
403
 
389
404
  require 'fileutils'
390
405
 
391
- %w[cache build_info doc gems specifications].each do |name|
406
+ REPOSITORY_SUBDIRECTORIES.each do |name|
392
407
  subdir = File.join dir, name
393
408
  next if File.exist? subdir
394
409
  FileUtils.mkdir_p subdir rescue nil # in case of perms issues -- lame
@@ -750,33 +765,35 @@ module Gem
750
765
  @ruby
751
766
  end
752
767
 
753
- # DOC: needs doc'd or :nodoc'd
768
+ ##
769
+ # Returns the latest release-version specification for the gem +name+.
770
+
754
771
  def self.latest_spec_for name
755
- dependency = Gem::Dependency.new name
756
- fetcher = Gem::SpecFetcher.fetcher
757
- spec_tuples = fetcher.find_matching dependency
772
+ dependency = Gem::Dependency.new name
773
+ fetcher = Gem::SpecFetcher.fetcher
774
+ spec_tuples, = fetcher.spec_for_dependency dependency
758
775
 
759
- match = spec_tuples.select { |(n, _, p), _|
760
- n == name and Gem::Platform.match p
761
- }.sort_by { |(_, version, _), _|
762
- version
763
- }.last
776
+ spec, = spec_tuples.first
764
777
 
765
- match and fetcher.fetch_spec(*match)
778
+ spec
766
779
  end
767
780
 
768
- # DOC: needs doc'd or :nodoc'd
769
- def self.latest_version_for name
770
- spec = latest_spec_for name
771
- spec and spec.version
772
- end
781
+ ##
782
+ # Returns the latest release version of RubyGems.
773
783
 
774
- # DOC: needs doc'd or :nodoc'd
775
784
  def self.latest_rubygems_version
776
- latest_version_for("rubygems-update") or
785
+ latest_version_for('rubygems-update') or
777
786
  raise "Can't find 'rubygems-update' in any repo. Check `gem source list`."
778
787
  end
779
788
 
789
+ ##
790
+ # Returns the version of the latest release-version of gem +name+
791
+
792
+ def self.latest_version_for name
793
+ spec = latest_spec_for name
794
+ spec and spec.version
795
+ end
796
+
780
797
  ##
781
798
  # A Gem::Version for the currently running ruby.
782
799
 
@@ -1,25 +1,44 @@
1
1
  require 'rubygems/command'
2
2
  require 'rubygems/version_option'
3
3
  require 'rubygems/validator'
4
+ require 'rubygems/doctor'
4
5
 
5
6
  class Gem::Commands::CheckCommand < Gem::Command
6
7
 
7
8
  include Gem::VersionOption
8
9
 
9
10
  def initialize
10
- super 'check', 'Check installed gems',
11
- :alien => true
11
+ super 'check', 'Check a gem repository for added or missing files',
12
+ :alien => true, :doctor => false, :dry_run => false, :gems => true
12
13
 
13
- add_option('-a', '--alien', "Report 'unmanaged' or rogue files in the",
14
- "gem repository") do |value, options|
15
- options[:alien] = true
14
+ add_option('-a', '--[no-]alien',
15
+ 'Report "unmanaged" or rogue files in the',
16
+ 'gem repository') do |value, options|
17
+ options[:alien] = value
18
+ end
19
+
20
+ add_option('--[no-]doctor',
21
+ 'Clean up uninstalled gems and broken',
22
+ 'specifications') do |value, options|
23
+ options[:doctor] = value
24
+ end
25
+
26
+ add_option('--[no-]dry-run',
27
+ 'Do not remove files, only report what',
28
+ 'would be removed') do |value, options|
29
+ options[:dry_run] = value
30
+ end
31
+
32
+ add_option('--[no-]gems',
33
+ 'Check installed gems for problems') do |value, options|
34
+ options[:gems] = value
16
35
  end
17
36
 
18
37
  add_version_option 'check'
19
38
  end
20
39
 
21
- def execute
22
- say "Checking gems..."
40
+ def check_gems
41
+ say 'Checking gems...'
23
42
  say
24
43
  gems = get_all_gem_names rescue []
25
44
 
@@ -37,4 +56,31 @@ class Gem::Commands::CheckCommand < Gem::Command
37
56
  end
38
57
  end
39
58
 
59
+ def doctor
60
+ say 'Checking for files from uninstalled gems...'
61
+ say
62
+
63
+ Gem.path.each do |gem_repo|
64
+ doctor = Gem::Doctor.new gem_repo, options[:dry_run]
65
+ doctor.doctor
66
+ end
67
+ end
68
+
69
+ def execute
70
+ check_gems if options[:gems]
71
+ doctor if options[:doctor]
72
+ end
73
+
74
+ def arguments # :nodoc:
75
+ 'GEMNAME name of gem to check'
76
+ end
77
+
78
+ def defaults_str # :nodoc:
79
+ '--gems --alien'
80
+ end
81
+
82
+ def usage # :nodoc:
83
+ "#{program_name} [OPTIONS] [GEMNAME ...]"
84
+ end
85
+
40
86
  end
@@ -12,6 +12,14 @@ class Gem::Commands::CleanupCommand < Gem::Command
12
12
  add_option('-d', '--dryrun', "") do |value, options|
13
13
  options[:dryrun] = true
14
14
  end
15
+
16
+ @candidate_gems = nil
17
+ @default_gems = []
18
+ @full = nil
19
+ @gems_to_cleanup = nil
20
+ @original_home = nil
21
+ @original_path = nil
22
+ @primary_gems = nil
15
23
  end
16
24
 
17
25
  def arguments # :nodoc:
@@ -38,79 +46,119 @@ are not removed.
38
46
 
39
47
  def execute
40
48
  say "Cleaning up installed gems..."
41
- primary_gems = {}
42
49
 
43
- Gem::Specification.each do |spec|
44
- if primary_gems[spec.name].nil? or
45
- primary_gems[spec.name].version < spec.version then
46
- primary_gems[spec.name] = spec
50
+ if options[:args].empty? then
51
+ done = false
52
+ last_set = nil
53
+
54
+ until done do
55
+ clean_gems
56
+
57
+ this_set = @gems_to_cleanup.map { |spec| spec.full_name }.sort
58
+
59
+ done = this_set.empty? || last_set == this_set
60
+
61
+ last_set = this_set
47
62
  end
63
+ else
64
+ clean_gems
48
65
  end
49
66
 
50
- candidate_gems = unless options[:args].empty? then
51
- options[:args].map do |gem_name|
52
- Gem::Specification.find_all_by_name gem_name
53
- end.flatten
54
- else
55
- Gem::Specification.to_a
56
- end
57
-
58
- gems_to_cleanup = candidate_gems.select { |spec|
59
- !spec.default_gem? and
60
- primary_gems[spec.name].version != spec.version
61
- }
67
+ say "Clean Up Complete"
62
68
 
63
- full = Gem::DependencyList.from_specs
69
+ if Gem.configuration.really_verbose then
70
+ skipped = @default_gems.map { |spec| spec.full_name }
71
+
72
+ say "Skipped default gems: #{skipped.join ', '}"
73
+ end
74
+ end
75
+
76
+ def clean_gems
77
+ get_primary_gems
78
+ get_candidate_gems
79
+ get_gems_to_cleanup
80
+
81
+ @full = Gem::DependencyList.from_specs
64
82
 
65
83
  deplist = Gem::DependencyList.new
66
- gems_to_cleanup.uniq.each do |spec| deplist.add spec end
84
+ @gems_to_cleanup.each do |spec| deplist.add spec end
85
+
86
+ deps = deplist.strongly_connected_components.flatten
67
87
 
68
- deps = deplist.strongly_connected_components.flatten.reverse
88
+ @original_home = Gem.dir
89
+ @original_path = Gem.path
69
90
 
70
- original_home = Gem.dir
71
- original_path = Gem.path
91
+ deps.reverse_each do |spec|
92
+ uninstall_dep spec
93
+ end
72
94
 
73
- deps.each do |spec|
74
- next unless full.ok_to_remove?(spec.full_name)
95
+ Gem::Specification.reset
96
+ end
75
97
 
76
- if options[:dryrun] then
77
- say "Dry Run Mode: Would uninstall #{spec.full_name}"
78
- else
79
- say "Attempting to uninstall #{spec.full_name}"
98
+ def get_candidate_gems
99
+ @candidate_gems = unless options[:args].empty? then
100
+ options[:args].map do |gem_name|
101
+ Gem::Specification.find_all_by_name gem_name
102
+ end.flatten
103
+ else
104
+ Gem::Specification.to_a
105
+ end
106
+ end
80
107
 
81
- options[:args] = [spec.name]
108
+ def get_gems_to_cleanup
109
+ gems_to_cleanup = @candidate_gems.select { |spec|
110
+ @primary_gems[spec.name].version != spec.version
111
+ }
82
112
 
83
- uninstall_options = {
84
- :executables => false,
85
- :version => "= #{spec.version}",
86
- }
113
+ default_gems, gems_to_cleanup = gems_to_cleanup.partition { |spec|
114
+ spec.default_gem?
115
+ }
87
116
 
88
- uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
117
+ @default_gems += default_gems
118
+ @default_gems.uniq!
119
+ @gems_to_cleanup = gems_to_cleanup.uniq
120
+ end
89
121
 
90
- uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
122
+ def get_primary_gems
123
+ @primary_gems = {}
91
124
 
92
- begin
93
- uninstaller.uninstall
94
- rescue Gem::DependencyRemovalException, Gem::InstallError,
95
- Gem::GemNotInHomeException, Gem::FilePermissionError => e
96
- say "Unable to uninstall #{spec.full_name}:"
97
- say "\t#{e.class}: #{e.message}"
98
- end
125
+ Gem::Specification.each do |spec|
126
+ if @primary_gems[spec.name].nil? or
127
+ @primary_gems[spec.name].version < spec.version then
128
+ @primary_gems[spec.name] = spec
99
129
  end
130
+ end
131
+ end
132
+
133
+ def uninstall_dep spec
134
+ return unless @full.ok_to_remove?(spec.full_name)
100
135
 
101
- # Restore path Gem::Uninstaller may have change
102
- Gem.use_paths(original_home, *original_path)
136
+ if options[:dryrun] then
137
+ say "Dry Run Mode: Would uninstall #{spec.full_name}"
138
+ return
103
139
  end
104
140
 
105
- say "Clean Up Complete"
141
+ say "Attempting to uninstall #{spec.full_name}"
106
142
 
107
- if Gem.configuration.really_verbose then
108
- skipped = candidate_gems.
109
- select { |spec| spec.default_gem? }.
110
- map { |spec| spec.full_name}
143
+ uninstall_options = {
144
+ :executables => false,
145
+ :version => "= #{spec.version}",
146
+ }
111
147
 
112
- say "Skipped default gems: #{skipped.join ', '}"
148
+ uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
149
+
150
+ uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
151
+
152
+ begin
153
+ uninstaller.uninstall
154
+ rescue Gem::DependencyRemovalException, Gem::InstallError,
155
+ Gem::GemNotInHomeException, Gem::FilePermissionError => e
156
+ say "Unable to uninstall #{spec.full_name}:"
157
+ say "\t#{e.class}: #{e.message}"
113
158
  end
159
+ ensure
160
+ # Restore path Gem::Uninstaller may have changed
161
+ Gem.use_paths @original_home, *@original_path
114
162
  end
115
163
 
116
164
  end
@@ -40,9 +40,17 @@ class Gem::Commands::PushCommand < Gem::Command
40
40
  def send_gem name
41
41
  args = [:post, "api/v1/gems"]
42
42
 
43
+ latest_rubygems_version = Gem.latest_rubygems_version
43
44
 
44
- if Gem.latest_rubygems_version < Gem::Version.new(Gem::VERSION) then
45
- alert_error "Using beta/unreleased version of rubygems. Not pushing."
45
+ if latest_rubygems_version < Gem.rubygems_version and
46
+ Gem.rubygems_version.prerelease? and
47
+ Gem::Version.new('2.0.0.preview3') != Gem.rubygems_version then
48
+ alert_error <<-ERROR
49
+ You are using a beta release of RubyGems (#{Gem::VERSION}) which is not
50
+ allowed to push gems. Please downgrade or upgrade to a release version.
51
+
52
+ The latest released RubyGems version is #{latest_rubygems_version}
53
+ ERROR
46
54
  terminate_interaction 1
47
55
  end
48
56
 
@@ -162,12 +162,18 @@ class Gem::Commands::QueryCommand < Gem::Command
162
162
  n.downcase
163
163
  end
164
164
 
165
+ output_versions output, versions
166
+
167
+ say output.join(options[:details] ? "\n\n" : "\n")
168
+ end
169
+
170
+ def output_versions output, versions
165
171
  versions.each do |gem_name, matching_tuples|
166
172
  matching_tuples = matching_tuples.sort_by { |n,_| n.version }.reverse
167
173
 
168
174
  platforms = Hash.new { |h,version| h[version] = [] }
169
175
 
170
- matching_tuples.map do |n,_|
176
+ matching_tuples.each do |n, _|
171
177
  platforms[n.version] << n.platform if n.platform
172
178
  end
173
179
 
@@ -182,97 +188,125 @@ class Gem::Commands::QueryCommand < Gem::Command
182
188
  end
183
189
  end
184
190
 
185
- entry = gem_name.dup
186
-
187
- if options[:versions] then
188
- list = if platforms.empty? or options[:details] then
189
- matching_tuples.map { |n,_| n.version }.uniq
190
- else
191
- platforms.sort.reverse.map do |version, pls|
192
- if pls == [Gem::Platform::RUBY] then
193
- version
194
- else
195
- ruby = pls.delete Gem::Platform::RUBY
196
- platform_list = [ruby, *pls.sort].compact
197
- "#{version} #{platform_list.join ' '}"
198
- end
199
- end
200
- end.join ', '
201
-
202
- entry << " (#{list})"
203
- end
204
-
205
- if options[:details] then
206
- detail_tuple = matching_tuples.first
191
+ output << make_entry(matching_tuples, platforms)
192
+ end
193
+ end
207
194
 
208
- spec = detail_tuple.last
195
+ def entry_details entry, spec, specs, platforms
196
+ return unless options[:details]
209
197
 
210
- unless spec.kind_of? Gem::Specification
211
- spec = spec.fetch_spec detail_tuple.first
212
- end
198
+ entry << "\n"
213
199
 
214
- entry << "\n"
200
+ spec_platforms entry, platforms
201
+ spec_authors entry, spec
202
+ spec_homepage entry, spec
203
+ spec_license entry, spec
204
+ spec_loaded_from entry, spec, specs
205
+ spec_summary entry, spec
206
+ end
215
207
 
216
- non_ruby = platforms.any? do |_, pls|
217
- pls.any? { |pl| pl != Gem::Platform::RUBY }
218
- end
208
+ def entry_versions entry, name_tuples, platforms
209
+ return unless options[:versions]
219
210
 
220
- if non_ruby then
221
- if platforms.length == 1 then
222
- title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
223
- entry << " #{title}: #{platforms.values.sort.join ', '}\n"
211
+ list =
212
+ if platforms.empty? or options[:details] then
213
+ name_tuples.map { |n| n.version }.uniq
214
+ else
215
+ platforms.sort.reverse.map do |version, pls|
216
+ if pls == [Gem::Platform::RUBY] then
217
+ version
224
218
  else
225
- entry << " Platforms:\n"
226
- platforms.sort_by do |version,|
227
- version
228
- end.each do |version, pls|
229
- label = " #{version}: "
230
- data = format_text pls.sort.join(', '), 68, label.length
231
- data[0, label.length] = label
232
- entry << data << "\n"
233
- end
219
+ ruby = pls.delete Gem::Platform::RUBY
220
+ platform_list = [ruby, *pls.sort].compact
221
+ "#{version} #{platform_list.join ' '}"
234
222
  end
235
223
  end
224
+ end
236
225
 
237
- authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
238
- authors << spec.authors.join(', ')
239
- entry << format_text(authors, 68, 4)
226
+ entry << " (#{list.join ', '})"
227
+ end
240
228
 
241
- if spec.rubyforge_project and not spec.rubyforge_project.empty? then
242
- rubyforge = "Rubyforge: http://rubyforge.org/projects/#{spec.rubyforge_project}"
243
- entry << "\n" << format_text(rubyforge, 68, 4)
244
- end
229
+ def make_entry entry_tuples, platforms
230
+ detail_tuple = entry_tuples.first
231
+ name_tuple, latest_spec = detail_tuple
245
232
 
246
- if spec.homepage and not spec.homepage.empty? then
247
- entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
248
- end
233
+ latest_spec = latest_spec.fetch_spec name_tuple unless
234
+ Gem::Specification === latest_spec
249
235
 
250
- if spec.license and not spec.license.empty? then
251
- licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
252
- licenses << spec.licenses.join(', ')
253
- entry << "\n" << format_text(licenses, 68, 4)
254
- end
236
+ name_tuples, specs = entry_tuples.flatten.partition do |item|
237
+ Gem::NameTuple === item
238
+ end
255
239
 
256
- if spec.loaded_from then
257
- if matching_tuples.length == 1 then
258
- loaded_from = File.dirname File.dirname(spec.loaded_from)
259
- entry << "\n" << " Installed at: #{loaded_from}"
260
- else
261
- label = 'Installed at'
262
- matching_tuples.each do |n,s|
263
- loaded_from = File.dirname File.dirname(s.loaded_from)
264
- entry << "\n" << " #{label} (#{n.version}): #{loaded_from}"
265
- label = ' ' * label.length
266
- end
267
- end
268
- end
240
+ entry = [latest_spec.name]
241
+
242
+ entry_versions entry, name_tuples, platforms
243
+ entry_details entry, latest_spec, specs, platforms
244
+
245
+ entry.join
246
+ end
247
+
248
+ def spec_authors entry, spec
249
+ authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
250
+ authors << spec.authors.join(', ')
251
+ entry << format_text(authors, 68, 4)
252
+ end
253
+
254
+ def spec_homepage entry, spec
255
+ return if spec.homepage.nil? or spec.homepage.empty?
256
+
257
+ entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
258
+ end
259
+
260
+ def spec_license entry, spec
261
+ return if spec.license.nil? or spec.license.empty?
269
262
 
270
- entry << "\n\n" << format_text(spec.summary, 68, 4)
263
+ licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
264
+ licenses << spec.licenses.join(', ')
265
+ entry << "\n" << format_text(licenses, 68, 4)
266
+ end
267
+
268
+ def spec_loaded_from entry, spec, specs
269
+ return unless spec.loaded_from
270
+
271
+ if specs.length == 1 then
272
+ default = spec.default_gem? ? ' (default)' : nil
273
+ entry << "\n" << " Installed at#{default}: #{spec.base_dir}"
274
+ else
275
+ label = 'Installed at'
276
+ specs.each do |s|
277
+ version = s.version.to_s
278
+ version << ', default' if s.default_gem?
279
+ entry << "\n" << " #{label} (#{version}): #{s.base_dir}"
280
+ label = ' ' * label.length
271
281
  end
272
- output << entry
273
282
  end
283
+ end
274
284
 
275
- say output.join(options[:details] ? "\n\n" : "\n")
285
+ def spec_platforms entry, platforms
286
+ non_ruby = platforms.any? do |_, pls|
287
+ pls.any? { |pl| pl != Gem::Platform::RUBY }
288
+ end
289
+
290
+ return unless non_ruby
291
+
292
+ if platforms.length == 1 then
293
+ title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
294
+ entry << " #{title}: #{platforms.values.sort.join ', '}\n"
295
+ else
296
+ entry << " Platforms:\n"
297
+ platforms.sort_by do |version,|
298
+ version
299
+ end.each do |version, pls|
300
+ label = " #{version}: "
301
+ data = format_text pls.sort.join(', '), 68, label.length
302
+ data[0, label.length] = label
303
+ entry << data << "\n"
304
+ end
305
+ end
306
+ end
307
+
308
+ def spec_summary entry, spec
309
+ entry << "\n\n" << format_text(spec.summary, 68, 4)
276
310
  end
277
311
 
278
312
  end