rubygems-update 1.2.0 → 1.3.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 (65) hide show
  1. data.tar.gz.sig +2 -4
  2. data/ChangeLog +155 -0
  3. data/Rakefile +20 -5
  4. data/doc/release_notes/rel_1_3_0.rdoc +125 -0
  5. data/lib/rubygems.rb +107 -15
  6. data/lib/rubygems/commands/contents_command.rb +1 -1
  7. data/lib/rubygems/commands/environment_command.rb +40 -0
  8. data/lib/rubygems/commands/help_command.rb +2 -2
  9. data/lib/rubygems/commands/install_command.rb +15 -0
  10. data/lib/rubygems/commands/lock_command.rb +15 -6
  11. data/lib/rubygems/commands/outdated_command.rb +1 -1
  12. data/lib/rubygems/commands/pristine_command.rb +1 -1
  13. data/lib/rubygems/commands/query_command.rb +14 -9
  14. data/lib/rubygems/commands/rdoc_command.rb +5 -1
  15. data/lib/rubygems/commands/specification_command.rb +2 -2
  16. data/lib/rubygems/commands/unpack_command.rb +1 -1
  17. data/lib/rubygems/commands/update_command.rb +23 -14
  18. data/lib/rubygems/commands/which_command.rb +4 -3
  19. data/lib/rubygems/config_file.rb +25 -3
  20. data/lib/rubygems/defaults.rb +42 -11
  21. data/lib/rubygems/dependency_installer.rb +19 -15
  22. data/lib/rubygems/doc_manager.rb +162 -115
  23. data/lib/rubygems/ext/builder.rb +2 -2
  24. data/lib/rubygems/ext/rake_builder.rb +1 -1
  25. data/lib/rubygems/gem_path_searcher.rb +35 -19
  26. data/lib/rubygems/indexer.rb +15 -6
  27. data/lib/rubygems/install_update_options.rb +7 -0
  28. data/lib/rubygems/installer.rb +85 -9
  29. data/lib/rubygems/local_remote_options.rb +7 -0
  30. data/lib/rubygems/package/tar_reader.rb +7 -7
  31. data/lib/rubygems/platform.rb +1 -18
  32. data/lib/rubygems/remote_fetcher.rb +45 -54
  33. data/lib/rubygems/rubygems_version.rb +1 -1
  34. data/lib/rubygems/source_index.rb +22 -7
  35. data/lib/rubygems/source_info_cache.rb +9 -0
  36. data/lib/rubygems/spec_fetcher.rb +18 -20
  37. data/lib/rubygems/specification.rb +502 -293
  38. data/lib/rubygems/test_utilities.rb +19 -8
  39. data/lib/rubygems/uninstaller.rb +60 -26
  40. data/setup.rb +15 -7
  41. data/test/gemutilities.rb +84 -0
  42. data/test/mockgemui.rb +22 -2
  43. data/test/test_gem.rb +118 -13
  44. data/test/test_gem_commands_dependency_command.rb +1 -1
  45. data/test/test_gem_commands_list_command.rb +37 -0
  46. data/test/test_gem_commands_lock_command.rb +69 -0
  47. data/test/test_gem_commands_query_command.rb +40 -1
  48. data/test/test_gem_commands_uninstall_command.rb +60 -0
  49. data/test/test_gem_config_file.rb +51 -17
  50. data/test/test_gem_ext_configure_builder.rb +9 -9
  51. data/test/test_gem_ext_rake_builder.rb +21 -12
  52. data/test/test_gem_gem_path_searcher.rb +15 -7
  53. data/test/test_gem_indexer.rb +35 -1
  54. data/test/test_gem_install_update_options.rb +26 -5
  55. data/test/test_gem_installer.rb +93 -21
  56. data/test/test_gem_local_remote_options.rb +12 -0
  57. data/test/test_gem_platform.rb +6 -13
  58. data/test/test_gem_remote_fetcher.rb +121 -31
  59. data/test/test_gem_source_index.rb +74 -21
  60. data/test/test_gem_source_info_cache.rb +2 -1
  61. data/test/test_gem_spec_fetcher.rb +13 -3
  62. data/test/test_gem_specification.rb +13 -7
  63. data/test/test_gem_uninstaller.rb +25 -2
  64. metadata +6 -2
  65. metadata.gz.sig +0 -0
@@ -2,5 +2,5 @@
2
2
  # This file is auto-generated by build scripts.
3
3
  # See: rake update_version
4
4
  module Gem
5
- RubyGemsVersion = '1.2.0'
5
+ RubyGemsVersion = '1.3.0'
6
6
  end
@@ -7,7 +7,9 @@
7
7
  require 'rubygems'
8
8
  require 'rubygems/user_interaction'
9
9
  require 'rubygems/specification'
10
- require 'rubygems/spec_fetcher'
10
+ module Gem
11
+ autoload(:SpecFetcher, 'rubygems/spec_fetcher')
12
+ end
11
13
 
12
14
  ##
13
15
  # The SourceIndex object indexes all the gems available from a
@@ -80,8 +82,14 @@ class Gem::SourceIndex
80
82
 
81
83
  def load_specification(file_name)
82
84
  begin
83
- spec_code = File.read(file_name).untaint
85
+ spec_code = if RUBY_VERSION < '1.9' then
86
+ File.read file_name
87
+ else
88
+ File.read file_name, :encoding => 'UTF-8'
89
+ end.untaint
90
+
84
91
  gemspec = eval spec_code, binding, file_name
92
+
85
93
  if gemspec.is_a?(Gem::Specification)
86
94
  gemspec.loaded_from = file_name
87
95
  return gemspec
@@ -93,7 +101,7 @@ class Gem::SourceIndex
93
101
  alert_warning e
94
102
  alert_warning spec_code
95
103
  rescue Exception => e
96
- alert_warning(e.inspect.to_s + "\n" + spec_code)
104
+ alert_warning "#{e.inspect}\n#{spec_code}"
97
105
  alert_warning "Invalid .gemspec format in '#{file_name}'"
98
106
  end
99
107
  return nil
@@ -230,7 +238,8 @@ class Gem::SourceIndex
230
238
  # Find a gem by an exact match on the short name.
231
239
 
232
240
  def find_name(gem_name, version_requirement = Gem::Requirement.default)
233
- search(/^#{gem_name}$/, version_requirement)
241
+ dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement)
242
+ search dep
234
243
  end
235
244
 
236
245
  ##
@@ -246,7 +255,13 @@ class Gem::SourceIndex
246
255
  version_requirement = nil
247
256
  only_platform = false
248
257
 
249
- case gem_pattern # TODO warn after 2008/03, remove three months after
258
+ # TODO - Remove support and warning for legacy arguments after 2008/11
259
+ unless Gem::Dependency === gem_pattern
260
+ warn "Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated"
261
+ warn "#{caller[0]} is outdated"
262
+ end
263
+
264
+ case gem_pattern
250
265
  when Regexp then
251
266
  version_requirement = platform_only || Gem::Requirement.default
252
267
  when Gem::Dependency then
@@ -270,7 +285,7 @@ class Gem::SourceIndex
270
285
 
271
286
  specs = @gems.values.select do |spec|
272
287
  spec.name =~ gem_pattern and
273
- version_requirement.satisfied_by? spec.version
288
+ version_requirement.satisfied_by? spec.version
274
289
  end
275
290
 
276
291
  if only_platform then
@@ -539,7 +554,7 @@ module Gem
539
554
  # objects to load properly.
540
555
  Cache = SourceIndex
541
556
 
542
- # :starddoc:
557
+ # :startdoc:
543
558
 
544
559
  end
545
560
 
@@ -284,6 +284,10 @@ class Gem::SourceInfoCache
284
284
 
285
285
  cache_data.map do |source_uri, sic_entry|
286
286
  next unless Gem.sources.include? source_uri
287
+ # TODO - Remove this gunk after 2008/11
288
+ unless pattern.kind_of?(Gem::Dependency)
289
+ pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
290
+ end
287
291
  sic_entry.source_index.search pattern, platform_only
288
292
  end.flatten.compact
289
293
  end
@@ -300,6 +304,11 @@ class Gem::SourceInfoCache
300
304
  cache_data.map do |source_uri, sic_entry|
301
305
  next unless Gem.sources.include? source_uri
302
306
 
307
+ # TODO - Remove this gunk after 2008/11
308
+ unless pattern.kind_of?(Gem::Dependency)
309
+ pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
310
+ end
311
+
303
312
  sic_entry.source_index.search(pattern, only_platform).each do |spec|
304
313
  results << [spec, source_uri]
305
314
  end
@@ -167,7 +167,7 @@ class Gem::SpecFetcher
167
167
 
168
168
  if all and @specs.include? source_uri then
169
169
  list[source_uri] = @specs[source_uri]
170
- elsif @latest_specs.include? source_uri then
170
+ elsif not all and @latest_specs.include? source_uri then
171
171
  list[source_uri] = @latest_specs[source_uri]
172
172
  else
173
173
  specs = load_specs source_uri, file
@@ -182,30 +182,28 @@ class Gem::SpecFetcher
182
182
  list
183
183
  end
184
184
 
185
- def load_specs(source_uri, file)
186
- file_name = "#{file}.#{Gem.marshal_version}.gz"
187
-
188
- spec_path = source_uri + file_name
189
-
190
- cache_dir = cache_dir spec_path
185
+ ##
186
+ # Loads specs in +file+, fetching from +source_uri+ if the on-disk cache is
187
+ # out of date.
191
188
 
192
- local_file = File.join(cache_dir, file_name).chomp '.gz'
189
+ def load_specs(source_uri, file)
190
+ file_name = "#{file}.#{Gem.marshal_version}"
191
+ spec_path = source_uri + "#{file_name}.gz"
192
+ cache_dir = cache_dir spec_path
193
+ local_file = File.join(cache_dir, file_name)
194
+ loaded = false
193
195
 
194
196
  if File.exist? local_file then
195
- local_size = File.stat(local_file).size
196
-
197
- remote_file = spec_path.dup
198
- remote_file.path = remote_file.path.chomp '.gz'
199
- remote_size = @fetcher.fetch_size remote_file
197
+ spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
200
198
 
201
- spec_dump = Gem.read_binary local_file if remote_size == local_size
202
- end
203
-
204
- unless spec_dump then
199
+ if spec_dump.nil? then
200
+ spec_dump = Gem.read_binary local_file
201
+ else
202
+ loaded = true
203
+ end
204
+ else
205
+ spec_dump = @fetcher.fetch_path spec_path
205
206
  loaded = true
206
-
207
- spec_dump_gz = @fetcher.fetch_path spec_path
208
- spec_dump = Gem.gunzip spec_dump_gz
209
207
  end
210
208
 
211
209
  specs = Marshal.load spec_dump
@@ -24,6 +24,7 @@ class Date; end # for ruby_code if date.rb wasn't required
24
24
 
25
25
  module Gem
26
26
 
27
+ ##
27
28
  # == Gem::Specification
28
29
  #
29
30
  # The Specification class contains the metadata for a Gem. Typically
@@ -38,7 +39,7 @@ module Gem
38
39
  #
39
40
  # There are many <em>gemspec attributes</em>, and the best place to learn
40
41
  # about them in the "Gemspec Reference" linked from the RubyGems wiki.
41
- #
42
+
42
43
  class Specification
43
44
 
44
45
  ##
@@ -46,8 +47,6 @@ module Gem
46
47
 
47
48
  attr_accessor :original_platform # :nodoc:
48
49
 
49
- # ------------------------- Specification version constants.
50
-
51
50
  ##
52
51
  # The the version number of a specification that does not specify one
53
52
  # (i.e. RubyGems 0.7 or earlier).
@@ -88,77 +87,98 @@ module Gem
88
87
  TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
89
88
  # :startdoc:
90
89
 
91
- # ------------------------- Class variables.
92
-
90
+ ##
93
91
  # List of Specification instances.
92
+
94
93
  @@list = []
95
94
 
95
+ ##
96
96
  # Optional block used to gather newly defined instances.
97
+
97
98
  @@gather = nil
98
99
 
100
+ ##
99
101
  # List of attribute names: [:name, :version, ...]
100
102
  @@required_attributes = []
101
103
 
102
- # List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...]
104
+ ##
105
+ # List of _all_ attributes and default values:
106
+ #
107
+ # [[:name, nil],
108
+ # [:bindir, 'bin'],
109
+ # ...]
110
+
103
111
  @@attributes = []
104
112
 
105
113
  @@nil_attributes = []
106
114
  @@non_nil_attributes = [:@original_platform]
107
115
 
116
+ ##
108
117
  # List of array attributes
118
+
109
119
  @@array_attributes = []
110
120
 
121
+ ##
111
122
  # Map of attribute names to default values.
123
+
112
124
  @@default_value = {}
113
125
 
114
- # ------------------------- Convenience class methods.
126
+ ##
127
+ # Names of all specification attributes
115
128
 
116
129
  def self.attribute_names
117
130
  @@attributes.map { |name, default| name }
118
131
  end
119
132
 
133
+ ##
134
+ # Default values for specification attributes
135
+
120
136
  def self.attribute_defaults
121
137
  @@attributes.dup
122
138
  end
123
139
 
140
+ ##
141
+ # The default value for specification attribute +name+
142
+
124
143
  def self.default_value(name)
125
144
  @@default_value[name]
126
145
  end
127
146
 
147
+ ##
148
+ # Required specification attributes
149
+
128
150
  def self.required_attributes
129
151
  @@required_attributes.dup
130
152
  end
131
153
 
154
+ ##
155
+ # Is +name+ a required attribute?
156
+
132
157
  def self.required_attribute?(name)
133
158
  @@required_attributes.include? name.to_sym
134
159
  end
135
160
 
161
+ ##
162
+ # Specification attributes that are arrays (appendable and so-forth)
163
+
136
164
  def self.array_attributes
137
165
  @@array_attributes.dup
138
166
  end
139
167
 
140
- # ------------------------- Infrastructure class methods.
168
+ ##
169
+ # A list of Specification instances that have been defined in this Ruby
170
+ # instance.
141
171
 
142
- # A list of Specification instances that have been defined in this Ruby instance.
143
172
  def self.list
144
173
  @@list
145
174
  end
146
175
 
147
- # Used to specify the name and default value of a specification
148
- # attribute. The side effects are:
149
- # * the name and default value are added to the @@attributes list
150
- # and @@default_value map
151
- # * a standard _writer_ method (<tt>attribute=</tt>) is created
152
- # * a non-standard _reader method (<tt>attribute</tt>) is created
153
- #
154
- # The reader method behaves like this:
155
- # def attribute
156
- # @attribute ||= (copy of default value)
157
- # end
158
- #
159
- # This allows lazy initialization of attributes to their default
160
- # values.
176
+ ##
177
+ # Specifies the +name+ and +default+ for a specification attribute, and
178
+ # creates a reader and writer method like Module#attr_accessor.
161
179
  #
180
+ # The reader method returns the default if the value hasn't been set.
181
+
162
182
  def self.attribute(name, default=nil)
163
183
  ivar_name = "@#{name}".intern
164
184
  if default.nil? then
@@ -172,8 +192,10 @@ module Gem
172
192
  attr_accessor(name)
173
193
  end
174
194
 
175
- # Same as :attribute, but ensures that values assigned to the
176
- # attribute are array values by applying :to_a to the value.
195
+ ##
196
+ # Same as :attribute, but ensures that values assigned to the attribute
197
+ # are array values by applying :to_a to the value.
198
+
177
199
  def self.array_attribute(name)
178
200
  @@non_nil_attributes << ["@#{name}".intern, []]
179
201
 
@@ -192,51 +214,60 @@ module Gem
192
214
  module_eval code, __FILE__, __LINE__ - 9
193
215
  end
194
216
 
217
+ ##
195
218
  # Same as attribute above, but also records this attribute as mandatory.
219
+
196
220
  def self.required_attribute(*args)
197
221
  @@required_attributes << args.first
198
222
  attribute(*args)
199
223
  end
200
224
 
201
- # Sometimes we don't want the world to use a setter method for a particular attribute.
225
+ ##
226
+ # Sometimes we don't want the world to use a setter method for a
227
+ # particular attribute.
228
+ #
202
229
  # +read_only+ makes it private so we can still use it internally.
230
+
203
231
  def self.read_only(*names)
204
232
  names.each do |name|
205
233
  private "#{name}="
206
234
  end
207
235
  end
208
236
 
209
- # Shortcut for creating several attributes at once (each with a default value of
210
- # +nil+).
237
+ # Shortcut for creating several attributes at once (each with a default
238
+ # value of +nil+).
239
+
211
240
  def self.attributes(*args)
212
241
  args.each do |arg|
213
242
  attribute(arg, nil)
214
243
  end
215
244
  end
216
245
 
217
- # Some attributes require special behaviour when they are accessed. This allows for
218
- # that.
246
+ ##
247
+ # Some attributes require special behaviour when they are accessed. This
248
+ # allows for that.
249
+
219
250
  def self.overwrite_accessor(name, &block)
220
251
  remove_method name
221
252
  define_method(name, &block)
222
253
  end
223
254
 
224
- # Defines a _singular_ version of an existing _plural_ attribute
225
- # (i.e. one whose value is expected to be an array). This means
226
- # just creating a helper method that takes a single value and
227
- # appends it to the array. These are created for convenience, so
228
- # that in a spec, one can write
255
+ ##
256
+ # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
257
+ # whose value is expected to be an array). This means just creating a
258
+ # helper method that takes a single value and appends it to the array.
259
+ # These are created for convenience, so that in a spec, one can write
229
260
  #
230
261
  # s.require_path = 'mylib'
231
262
  #
232
- # instead of
263
+ # instead of:
233
264
  #
234
265
  # s.require_paths = ['mylib']
235
266
  #
236
- # That above convenience is available courtesy of
267
+ # That above convenience is available courtesy of:
237
268
  #
238
269
  # attribute_alias_singular :require_path, :require_paths
239
- #
270
+
240
271
  def self.attribute_alias_singular(singular, plural)
241
272
  define_method("#{singular}=") { |val|
242
273
  send("#{plural}=", [val])
@@ -320,189 +351,45 @@ module Gem
320
351
  spec
321
352
  end
322
353
 
323
- # REQUIRED gemspec attributes ------------------------------------
324
-
325
- required_attribute :rubygems_version, Gem::RubyGemsVersion
326
- required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
327
- required_attribute :name
328
- required_attribute :version
329
- required_attribute :date, TODAY
330
- required_attribute :summary
331
- required_attribute :require_paths, ['lib']
332
-
333
- # OPTIONAL gemspec attributes ------------------------------------
334
-
335
- attributes :email, :homepage, :rubyforge_project, :description
336
- attributes :autorequire, :default_executable
337
-
338
- attribute :bindir, 'bin'
339
- attribute :has_rdoc, false
340
- attribute :required_ruby_version, Gem::Requirement.default
341
- attribute :required_rubygems_version, Gem::Requirement.default
342
- attribute :platform, Gem::Platform::RUBY
343
-
344
- attribute :signing_key, nil
345
- attribute :cert_chain, []
346
- attribute :post_install_message, nil
347
-
348
- array_attribute :authors
349
- array_attribute :files
350
- array_attribute :test_files
351
- array_attribute :rdoc_options
352
- array_attribute :extra_rdoc_files
353
- array_attribute :executables
354
-
355
- # Array of extensions to build. See Gem::Installer#build_extensions for
356
- # valid values.
357
-
358
- array_attribute :extensions
359
- array_attribute :requirements
360
- array_attribute :dependencies
361
-
362
- read_only :dependencies
354
+ ##
355
+ # List of depedencies that will automatically be activated at runtime.
363
356
 
364
357
  def runtime_dependencies
365
358
  dependencies.select { |d| d.type == :runtime || d.type == nil }
366
359
  end
367
360
 
361
+ ##
362
+ # List of dependencies that are used for development
363
+
368
364
  def development_dependencies
369
365
  dependencies.select { |d| d.type == :development }
370
366
  end
371
367
 
372
- # ALIASED gemspec attributes -------------------------------------
373
-
374
- attribute_alias_singular :executable, :executables
375
- attribute_alias_singular :author, :authors
376
- attribute_alias_singular :require_path, :require_paths
377
- attribute_alias_singular :test_file, :test_files
378
-
379
- # DEPRECATED gemspec attributes ----------------------------------
380
-
381
- def test_suite_file
368
+ def test_suite_file # :nodoc:
382
369
  warn 'test_suite_file deprecated, use test_files'
383
370
  test_files.first
384
371
  end
385
372
 
386
- def test_suite_file=(val)
373
+ def test_suite_file=(val) # :nodoc:
387
374
  warn 'test_suite_file= deprecated, use test_files='
388
375
  @test_files = [] unless defined? @test_files
389
376
  @test_files << val
390
377
  end
391
378
 
379
+ ##
392
380
  # true when this gemspec has been loaded from a specifications directory.
393
381
  # This attribute is not persisted.
394
382
 
395
- attr_writer :loaded
383
+ attr_accessor :loaded
396
384
 
385
+ ##
397
386
  # Path this gemspec was loaded from. This attribute is not persisted.
398
- attr_accessor :loaded_from
399
-
400
- # Special accessor behaviours (overwriting default) --------------
401
-
402
- overwrite_accessor :version= do |version|
403
- @version = Version.create(version)
404
- end
405
-
406
- overwrite_accessor :platform do
407
- @new_platform
408
- end
409
-
410
- overwrite_accessor :platform= do |platform|
411
- if @original_platform.nil? or
412
- @original_platform == Gem::Platform::RUBY then
413
- @original_platform = platform
414
- end
415
-
416
- case platform
417
- when Gem::Platform::CURRENT then
418
- @new_platform = Gem::Platform.local
419
- @original_platform = @new_platform.to_s
420
-
421
- when Gem::Platform then
422
- @new_platform = platform
423
-
424
- # legacy constants
425
- when nil, Gem::Platform::RUBY then
426
- @new_platform = Gem::Platform::RUBY
427
- when 'mswin32' then # was Gem::Platform::WIN32
428
- @new_platform = Gem::Platform.new 'x86-mswin32'
429
- when 'i586-linux' then # was Gem::Platform::LINUX_586
430
- @new_platform = Gem::Platform.new 'x86-linux'
431
- when 'powerpc-darwin' then # was Gem::Platform::DARWIN
432
- @new_platform = Gem::Platform.new 'ppc-darwin'
433
- else
434
- @new_platform = Gem::Platform.new platform
435
- end
436
-
437
- @platform = @new_platform.to_s
438
-
439
- @new_platform
440
- end
441
-
442
- overwrite_accessor :required_ruby_version= do |value|
443
- @required_ruby_version = Gem::Requirement.create(value)
444
- end
445
-
446
- overwrite_accessor :required_rubygems_version= do |value|
447
- @required_rubygems_version = Gem::Requirement.create(value)
448
- end
449
-
450
- overwrite_accessor :date= do |date|
451
- # We want to end up with a Time object with one-day resolution.
452
- # This is the cleanest, most-readable, faster-than-using-Date
453
- # way to do it.
454
- case date
455
- when String then
456
- @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
457
- Time.local($1.to_i, $2.to_i, $3.to_i)
458
- else
459
- require 'time'
460
- Time.parse date
461
- end
462
- when Time then
463
- @date = Time.local(date.year, date.month, date.day)
464
- when Date then
465
- @date = Time.local(date.year, date.month, date.day)
466
- else
467
- @date = TODAY
468
- end
469
- end
470
-
471
- overwrite_accessor :date do
472
- self.date = nil if @date.nil? # HACK Sets the default value for date
473
- @date
474
- end
475
-
476
- overwrite_accessor :summary= do |str|
477
- @summary = if str then
478
- str.strip.
479
- gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
480
- gsub(/\n[ \t]*/, " ")
481
- end
482
- end
483
387
 
484
- overwrite_accessor :description= do |str|
485
- @description = if str then
486
- str.strip.
487
- gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
488
- gsub(/\n[ \t]*/, " ")
489
- end
490
- end
388
+ attr_accessor :loaded_from
491
389
 
492
- overwrite_accessor :default_executable do
493
- begin
494
- if defined?(@default_executable) and @default_executable
495
- result = @default_executable
496
- elsif @executables and @executables.size == 1
497
- result = Array(@executables).first
498
- else
499
- result = nil
500
- end
501
- result
502
- rescue
503
- nil
504
- end
505
- end
390
+ ##
391
+ # Returns an array with bindir attached to each executable in the
392
+ # executables list
506
393
 
507
394
  def add_bindir(executables)
508
395
  return nil if executables.nil?
@@ -516,17 +403,9 @@ module Gem
516
403
  return nil
517
404
  end
518
405
 
519
- overwrite_accessor :files do
520
- result = []
521
- result.push(*@files) if defined?(@files)
522
- result.push(*@test_files) if defined?(@test_files)
523
- result.push(*(add_bindir(@executables)))
524
- result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
525
- result.push(*@extensions) if defined?(@extensions)
526
- result.uniq.compact
527
- end
528
-
406
+ ##
529
407
  # Files in the Gem under one of the require_paths
408
+
530
409
  def lib_files
531
410
  @files.select do |file|
532
411
  require_paths.any? do |path|
@@ -535,34 +414,25 @@ module Gem
535
414
  end
536
415
  end
537
416
 
538
- overwrite_accessor :test_files do
539
- # Handle the possibility that we have @test_suite_file but not
540
- # @test_files. This will happen when an old gem is loaded via
541
- # YAML.
542
- if defined? @test_suite_file then
543
- @test_files = [@test_suite_file].flatten
544
- @test_suite_file = nil
545
- end
546
- if defined?(@test_files) and @test_files then
547
- @test_files
548
- else
549
- @test_files = []
550
- end
417
+ ##
418
+ # True if this gem was loaded from disk
419
+
420
+ alias :loaded? :loaded
421
+
422
+ ##
423
+ # True if this gem has files in test_files
424
+
425
+ def has_unit_tests?
426
+ not test_files.empty?
551
427
  end
552
428
 
553
- # Predicates -----------------------------------------------------
554
-
555
- def loaded?; @loaded ? true : false ; end
556
- def has_rdoc?; has_rdoc ? true : false ; end
557
- def has_unit_tests?; not test_files.empty?; end
558
- alias has_test_suite? has_unit_tests? # (deprecated)
559
-
560
- # Constructors ---------------------------------------------------
429
+ alias has_test_suite? has_unit_tests? # :nodoc: deprecated
561
430
 
431
+ ##
562
432
  # Specification constructor. Assigns the default values to the
563
433
  # attributes, adds this spec to the list of loaded specs (see
564
434
  # Specification.list), and yields itself for further initialization.
565
- #
435
+
566
436
  def initialize
567
437
  @new_platform = nil
568
438
  assign_defaults
@@ -575,11 +445,13 @@ module Gem
575
445
  @@gather.call(self) if @@gather
576
446
  end
577
447
 
578
- # Each attribute has a default value (possibly nil). Here, we
579
- # initialize all attributes to their default value. This is
580
- # done through the accessor methods, so special behaviours will
581
- # be honored. Furthermore, we take a _copy_ of the default so
582
- # each specification instance has its own empty arrays, etc.
448
+ ##
449
+ # Each attribute has a default value (possibly nil). Here, we initialize
450
+ # all attributes to their default value. This is done through the
451
+ # accessor methods, so special behaviours will be honored. Furthermore,
452
+ # we take a _copy_ of the default so each specification instance has its
453
+ # own empty arrays, etc.
454
+
583
455
  def assign_defaults
584
456
  @@nil_attributes.each do |name|
585
457
  instance_variable_set name, nil
@@ -598,13 +470,14 @@ module Gem
598
470
  instance_variable_set :@new_platform, Gem::Platform::RUBY
599
471
  end
600
472
 
601
- # Special loader for YAML files. When a Specification object is
602
- # loaded from a YAML file, it bypasses the normal Ruby object
603
- # initialization routine (#initialize). This method makes up for
604
- # that and deals with gems of different ages.
473
+ ##
474
+ # Special loader for YAML files. When a Specification object is loaded
475
+ # from a YAML file, it bypasses the normal Ruby object initialization
476
+ # routine (#initialize). This method makes up for that and deals with
477
+ # gems of different ages.
605
478
  #
606
479
  # 'input' can be anything that YAML.load() accepts: String or IO.
607
- #
480
+
608
481
  def self.from_yaml(input)
609
482
  input = normalize_yaml_input input
610
483
  spec = YAML.load input
@@ -627,6 +500,9 @@ module Gem
627
500
  spec
628
501
  end
629
502
 
503
+ ##
504
+ # Loads ruby format gemspec from +filename+
505
+
630
506
  def self.load(filename)
631
507
  gemspec = nil
632
508
  fail "NESTED Specification.load calls not allowed!" if @@gather
@@ -638,22 +514,25 @@ module Gem
638
514
  @@gather = nil
639
515
  end
640
516
 
641
- # Make sure the yaml specification is properly formatted with dashes.
517
+ ##
518
+ # Make sure the YAML specification is properly formatted with dashes
519
+
642
520
  def self.normalize_yaml_input(input)
643
521
  result = input.respond_to?(:read) ? input.read : input
644
522
  result = "--- " + result unless result =~ /^--- /
645
523
  result
646
524
  end
647
525
 
648
- # Instance methods -----------------------------------------------
649
-
650
- # Sets the rubygems_version to Gem::RubyGemsVersion.
651
- #
526
+ ##
527
+ # Sets the rubygems_version to the current RubyGems version
528
+
652
529
  def mark_version
653
530
  @rubygems_version = RubyGemsVersion
654
531
  end
655
532
 
656
- # Ignore unknown attributes if the
533
+ ##
534
+ # Ignore unknown attributes while loading
535
+
657
536
  def method_missing(sym, *a, &b) # :nodoc:
658
537
  if @specification_version > CURRENT_SPECIFICATION_VERSION and
659
538
  sym.to_s =~ /=$/ then
@@ -663,35 +542,39 @@ module Gem
663
542
  end
664
543
  end
665
544
 
666
- # Adds a development dependency to this Gem. For example,
667
- #
668
- # spec.add_development_dependency('jabber4r', '> 0.1', '<= 0.5')
545
+ ##
546
+ # Adds a development dependency named +gem+ with +requirements+ to this
547
+ # Gem. For example:
669
548
  #
670
- # Development dependencies aren't installed by default, and
671
- # aren't activated when a gem is required.
549
+ # spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
672
550
  #
673
- # gem:: [String or Gem::Dependency] The Gem name/dependency.
674
- # requirements:: [default=">= 0"] The version requirements.
551
+ # Development dependencies aren't installed by default and aren't
552
+ # activated when a gem is required.
553
+
675
554
  def add_development_dependency(gem, *requirements)
676
555
  add_dependency_with_type(gem, :development, *requirements)
677
556
  end
678
557
 
679
- # Adds a runtime dependency to this Gem. For example,
680
- #
681
- # spec.add_runtime_dependency('jabber4r', '> 0.1', '<= 0.5')
558
+ ##
559
+ # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
560
+ # For example:
682
561
  #
683
- # gem:: [String or Gem::Dependency] The Gem name/dependency.
684
- # requirements:: [default=">= 0"] The version requirements.
562
+ # spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
563
+
685
564
  def add_runtime_dependency(gem, *requirements)
686
565
  add_dependency_with_type(gem, :runtime, *requirements)
687
566
  end
688
567
 
568
+ ##
569
+ # Adds a runtime dependency
570
+
689
571
  alias add_dependency add_runtime_dependency
690
572
 
573
+ ##
691
574
  # Returns the full name (name-version) of this Gem. Platform information
692
- # is included (name-version-platform) if it is specified (and not the
693
- # default Ruby platform).
694
- #
575
+ # is included (name-version-platform) if it is specified and not the
576
+ # default Ruby platform.
577
+
695
578
  def full_name
696
579
  if platform == Gem::Platform::RUBY or platform.nil? then
697
580
  "#{@name}-#{@version}"
@@ -700,9 +583,10 @@ module Gem
700
583
  end
701
584
  end
702
585
 
586
+ ##
703
587
  # Returns the full name (name-version) of this gemspec using the original
704
- # platform.
705
- #
588
+ # platform. For use with legacy gems.
589
+
706
590
  def original_name # :nodoc:
707
591
  if platform == Gem::Platform::RUBY or platform.nil? then
708
592
  "#{@name}-#{@version}"
@@ -736,18 +620,16 @@ module Gem
736
620
  File.expand_path path
737
621
  end
738
622
 
739
- # Checks if this Specification meets the requirement of the supplied
740
- # dependency.
741
- #
742
- # dependency:: [Gem::Dependency] the dependency to check
743
- # return:: [Boolean] true if dependency is met, otherwise false
744
- #
623
+ ##
624
+ # Checks if this specification meets the requirement of +dependency+.
625
+
745
626
  def satisfies_requirement?(dependency)
746
627
  return @name == dependency.name &&
747
628
  dependency.version_requirements.satisfied_by?(@version)
748
629
  end
749
630
 
750
- # Comparison methods ---------------------------------------------
631
+ ##
632
+ # Returns an object you can use to sort specifications in #sort_by.
751
633
 
752
634
  def sort_obj
753
635
  [@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
@@ -757,19 +639,25 @@ module Gem
757
639
  sort_obj <=> other.sort_obj
758
640
  end
759
641
 
642
+ ##
760
643
  # Tests specs for equality (across all attributes).
644
+
761
645
  def ==(other) # :nodoc:
762
646
  self.class === other && same_attributes?(other)
763
647
  end
764
648
 
765
649
  alias eql? == # :nodoc:
766
650
 
651
+ ##
652
+ # True if this gem has the same attributes as +other+.
653
+
767
654
  def same_attributes?(other)
768
655
  @@attributes.each do |name, default|
769
656
  return false unless self.send(name) == other.send(name)
770
657
  end
771
658
  true
772
659
  end
660
+
773
661
  private :same_attributes?
774
662
 
775
663
  def hash # :nodoc:
@@ -779,8 +667,6 @@ module Gem
779
667
  }
780
668
  end
781
669
 
782
- # Export methods (YAML and Ruby code) ----------------------------
783
-
784
670
  def to_yaml(opts = {}) # :nodoc:
785
671
  mark_version
786
672
 
@@ -825,6 +711,8 @@ module Gem
825
711
  def to_ruby
826
712
  mark_version
827
713
  result = []
714
+ result << "# -*- encoding: utf-8 -*-"
715
+ result << nil
828
716
  result << "Gem::Specification.new do |s|"
829
717
 
830
718
  result << " s.name = #{ruby_code name}"
@@ -861,7 +749,7 @@ module Gem
861
749
  result << " s.specification_version = #{specification_version}"
862
750
  result << nil
863
751
 
864
- result << " if current_version >= 3 then"
752
+ result << " if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
865
753
 
866
754
  unless dependencies.empty? then
867
755
  dependencies.each do |dep|
@@ -895,16 +783,15 @@ module Gem
895
783
  result.join "\n"
896
784
  end
897
785
 
898
- # Validation and normalization methods ---------------------------
899
-
900
- # Checks that the specification contains all required fields, and
901
- # does a very basic sanity check.
786
+ ##
787
+ # Checks that the specification contains all required fields, and does a
788
+ # very basic sanity check.
902
789
  #
903
- # Raises InvalidSpecificationException if the spec does not pass
904
- # the checks..
790
+ # Raises InvalidSpecificationException if the spec does not pass the
791
+ # checks..
792
+
905
793
  def validate
906
794
  extend Gem::UserInteraction
907
-
908
795
  normalize
909
796
 
910
797
  if rubygems_version != RubyGemsVersion then
@@ -959,13 +846,14 @@ module Gem
959
846
  true
960
847
  end
961
848
 
849
+ ##
962
850
  # Normalize the list of files so that:
963
851
  # * All file lists have redundancies removed.
964
- # * Files referenced in the extra_rdoc_files are included in the
965
- # package file list.
852
+ # * Files referenced in the extra_rdoc_files are included in the package
853
+ # file list.
966
854
  #
967
- # Also, the summary and description are converted to a normal
968
- # format.
855
+ # Also, the summary and description are converted to a normal format.
856
+
969
857
  def normalize
970
858
  if defined?(@extra_rdoc_files) and @extra_rdoc_files then
971
859
  @extra_rdoc_files.uniq!
@@ -975,15 +863,12 @@ module Gem
975
863
  @files.uniq! if @files
976
864
  end
977
865
 
978
- # Dependency methods ---------------------------------------------
979
-
980
- # Return a list of all gems that have a dependency on this
981
- # gemspec. The list is structured with entries that conform to:
866
+ ##
867
+ # Return a list of all gems that have a dependency on this gemspec. The
868
+ # list is structured with entries that conform to:
982
869
  #
983
870
  # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
984
- #
985
- # return:: [Array] [[dependent_gem, dependency, [list_of_satisfiers]]]
986
- #
871
+
987
872
  def dependent_gems
988
873
  out = []
989
874
  Gem.source_index.each do |name,gem|
@@ -1004,8 +889,6 @@ module Gem
1004
889
  "#<Gem::Specification name=#{@name} version=#{@version}>"
1005
890
  end
1006
891
 
1007
- private
1008
-
1009
892
  def add_dependency_with_type(dependency, type, *requirements)
1010
893
  requirements = if requirements.empty? then
1011
894
  Gem::Requirement.default
@@ -1022,6 +905,8 @@ module Gem
1022
905
  dependencies << dependency
1023
906
  end
1024
907
 
908
+ private :add_dependency_with_type
909
+
1025
910
  def find_all_satisfiers(dep)
1026
911
  Gem.source_index.each do |name,gem|
1027
912
  if(gem.satisfies_requirement?(dep)) then
@@ -1030,8 +915,12 @@ module Gem
1030
915
  end
1031
916
  end
1032
917
 
1033
- # Return a string containing a Ruby code representation of the
1034
- # given object.
918
+ private :find_all_satisfiers
919
+
920
+ ##
921
+ # Return a string containing a Ruby code representation of the given
922
+ # object.
923
+
1035
924
  def ruby_code(obj)
1036
925
  case obj
1037
926
  when String then '%q{' + obj + '}'
@@ -1046,6 +935,326 @@ module Gem
1046
935
  else raise Exception, "ruby_code case not handled: #{obj.class}"
1047
936
  end
1048
937
  end
938
+
939
+ private :ruby_code
940
+
941
+ # :section: Required gemspec attributes
942
+
943
+ ##
944
+ # The version of RubyGems used to create this gem
945
+
946
+ required_attribute :rubygems_version, Gem::RubyGemsVersion
947
+
948
+ ##
949
+ # The Gem::Specification version of this gemspec
950
+
951
+ required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
952
+
953
+ ##
954
+ # This gem's name
955
+
956
+ required_attribute :name
957
+
958
+ ##
959
+ # This gem's version
960
+
961
+ required_attribute :version
962
+
963
+ ##
964
+ # The date this gem was created
965
+
966
+ required_attribute :date, TODAY
967
+
968
+ ##
969
+ # A short summary of this gem's description. Displayed in `gem list -d`.
970
+
971
+ required_attribute :summary
972
+
973
+ ##
974
+ # Paths in the gem to add to $LOAD_PATH when this gem is activated
975
+
976
+ required_attribute :require_paths, ['lib']
977
+
978
+ # :section: Optional gemspec attributes
979
+
980
+ ##
981
+ # A contact email for this gem
982
+
983
+ attribute :email
984
+
985
+ ##
986
+ # The URL of this gem's home page
987
+
988
+ attribute :homepage
989
+
990
+ ##
991
+ # The rubyforge project this gem lives under. i.e. RubyGems'
992
+ # rubyforge_project is "rubygems".
993
+
994
+ attribute :rubyforge_project
995
+
996
+ ##
997
+ # A long description of this gem
998
+
999
+ attribute :description
1000
+
1001
+ ##
1002
+ # Autorequire was used by old RubyGems to automatically require a file.
1003
+ # It no longer is supported.
1004
+
1005
+ attribute :autorequire
1006
+
1007
+ ##
1008
+ # The default executable for this gem.
1009
+
1010
+ attribute :default_executable
1011
+
1012
+ ##
1013
+ # The path in the gem for executable scripts
1014
+
1015
+ attribute :bindir, 'bin'
1016
+
1017
+ ##
1018
+ # True if this gem is RDoc-compliant
1019
+
1020
+ attribute :has_rdoc, false
1021
+
1022
+ ##
1023
+ # True if this gem supports RDoc
1024
+
1025
+ alias :has_rdoc? :has_rdoc
1026
+
1027
+ ##
1028
+ # The ruby of version required by this gem
1029
+
1030
+ attribute :required_ruby_version, Gem::Requirement.default
1031
+
1032
+ ##
1033
+ # The RubyGems version required by this gem
1034
+
1035
+ attribute :required_rubygems_version, Gem::Requirement.default
1036
+
1037
+ ##
1038
+ # The platform this gem runs on. See Gem::Platform for details.
1039
+
1040
+ attribute :platform, Gem::Platform::RUBY
1041
+
1042
+ ##
1043
+ # The key used to sign this gem. See Gem::Security for details.
1044
+
1045
+ attribute :signing_key, nil
1046
+
1047
+ ##
1048
+ # The certificate chain used to sign this gem. See Gem::Security for
1049
+ # details.
1050
+
1051
+ attribute :cert_chain, []
1052
+
1053
+ ##
1054
+ # A message that gets displayed after the gem is installed
1055
+
1056
+ attribute :post_install_message, nil
1057
+
1058
+ ##
1059
+ # The list of authors who wrote this gem
1060
+
1061
+ array_attribute :authors
1062
+
1063
+ ##
1064
+ # Files included in this gem
1065
+
1066
+ array_attribute :files
1067
+
1068
+ ##
1069
+ # Test files included in this gem
1070
+
1071
+ array_attribute :test_files
1072
+
1073
+ ##
1074
+ # An ARGV-style array of options to RDoc
1075
+
1076
+ array_attribute :rdoc_options
1077
+
1078
+ ##
1079
+ # Extra files to add to RDoc
1080
+
1081
+ array_attribute :extra_rdoc_files
1082
+
1083
+ ##
1084
+ # Executables included in the gem
1085
+
1086
+ array_attribute :executables
1087
+
1088
+ ##
1089
+ # Extensions to build when installing the gem. See
1090
+ # Gem::Installer#build_extensions for valid values.
1091
+
1092
+ array_attribute :extensions
1093
+
1094
+ ##
1095
+ # An array or things required by this gem. Not used by anything
1096
+ # presently.
1097
+
1098
+ array_attribute :requirements
1099
+
1100
+ ##
1101
+ # A list of Gem::Dependency objects this gem depends on. Only appendable.
1102
+
1103
+ array_attribute :dependencies
1104
+
1105
+ read_only :dependencies
1106
+
1107
+ # :section: Aliased gemspec attributes
1108
+
1109
+ ##
1110
+ # Singular accessor for executables
1111
+
1112
+ attribute_alias_singular :executable, :executables
1113
+
1114
+ ##
1115
+ # Singular accessor for authors
1116
+
1117
+ attribute_alias_singular :author, :authors
1118
+
1119
+ ##
1120
+ # Singular accessor for require_paths
1121
+
1122
+ attribute_alias_singular :require_path, :require_paths
1123
+
1124
+ ##
1125
+ # Singular accessor for test_files
1126
+
1127
+ attribute_alias_singular :test_file, :test_files
1128
+
1129
+ overwrite_accessor :version= do |version|
1130
+ @version = Version.create(version)
1131
+ end
1132
+
1133
+ overwrite_accessor :platform do
1134
+ @new_platform
1135
+ end
1136
+
1137
+ overwrite_accessor :platform= do |platform|
1138
+ if @original_platform.nil? or
1139
+ @original_platform == Gem::Platform::RUBY then
1140
+ @original_platform = platform
1141
+ end
1142
+
1143
+ case platform
1144
+ when Gem::Platform::CURRENT then
1145
+ @new_platform = Gem::Platform.local
1146
+ @original_platform = @new_platform.to_s
1147
+
1148
+ when Gem::Platform then
1149
+ @new_platform = platform
1150
+
1151
+ # legacy constants
1152
+ when nil, Gem::Platform::RUBY then
1153
+ @new_platform = Gem::Platform::RUBY
1154
+ when 'mswin32' then # was Gem::Platform::WIN32
1155
+ @new_platform = Gem::Platform.new 'x86-mswin32'
1156
+ when 'i586-linux' then # was Gem::Platform::LINUX_586
1157
+ @new_platform = Gem::Platform.new 'x86-linux'
1158
+ when 'powerpc-darwin' then # was Gem::Platform::DARWIN
1159
+ @new_platform = Gem::Platform.new 'ppc-darwin'
1160
+ else
1161
+ @new_platform = Gem::Platform.new platform
1162
+ end
1163
+
1164
+ @platform = @new_platform.to_s
1165
+
1166
+ @new_platform
1167
+ end
1168
+
1169
+ overwrite_accessor :required_ruby_version= do |value|
1170
+ @required_ruby_version = Gem::Requirement.create(value)
1171
+ end
1172
+
1173
+ overwrite_accessor :required_rubygems_version= do |value|
1174
+ @required_rubygems_version = Gem::Requirement.create(value)
1175
+ end
1176
+
1177
+ overwrite_accessor :date= do |date|
1178
+ # We want to end up with a Time object with one-day resolution.
1179
+ # This is the cleanest, most-readable, faster-than-using-Date
1180
+ # way to do it.
1181
+ case date
1182
+ when String then
1183
+ @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
1184
+ Time.local($1.to_i, $2.to_i, $3.to_i)
1185
+ else
1186
+ require 'time'
1187
+ Time.parse date
1188
+ end
1189
+ when Time then
1190
+ @date = Time.local(date.year, date.month, date.day)
1191
+ when Date then
1192
+ @date = Time.local(date.year, date.month, date.day)
1193
+ else
1194
+ @date = TODAY
1195
+ end
1196
+ end
1197
+
1198
+ overwrite_accessor :date do
1199
+ self.date = nil if @date.nil? # HACK Sets the default value for date
1200
+ @date
1201
+ end
1202
+
1203
+ overwrite_accessor :summary= do |str|
1204
+ @summary = if str then
1205
+ str.strip.
1206
+ gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
1207
+ gsub(/\n[ \t]*/, " ")
1208
+ end
1209
+ end
1210
+
1211
+ overwrite_accessor :description= do |str|
1212
+ @description = if str then
1213
+ str.strip.
1214
+ gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
1215
+ gsub(/\n[ \t]*/, " ")
1216
+ end
1217
+ end
1218
+
1219
+ overwrite_accessor :default_executable do
1220
+ begin
1221
+ if defined?(@default_executable) and @default_executable
1222
+ result = @default_executable
1223
+ elsif @executables and @executables.size == 1
1224
+ result = Array(@executables).first
1225
+ else
1226
+ result = nil
1227
+ end
1228
+ result
1229
+ rescue
1230
+ nil
1231
+ end
1232
+ end
1233
+
1234
+ overwrite_accessor :test_files do
1235
+ # Handle the possibility that we have @test_suite_file but not
1236
+ # @test_files. This will happen when an old gem is loaded via
1237
+ # YAML.
1238
+ if defined? @test_suite_file then
1239
+ @test_files = [@test_suite_file].flatten
1240
+ @test_suite_file = nil
1241
+ end
1242
+ if defined?(@test_files) and @test_files then
1243
+ @test_files
1244
+ else
1245
+ @test_files = []
1246
+ end
1247
+ end
1248
+
1249
+ overwrite_accessor :files do
1250
+ result = []
1251
+ result.push(*@files) if defined?(@files)
1252
+ result.push(*@test_files) if defined?(@test_files)
1253
+ result.push(*(add_bindir(@executables)))
1254
+ result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
1255
+ result.push(*@extensions) if defined?(@extensions)
1256
+ result.uniq.compact
1257
+ end
1049
1258
 
1050
1259
  end
1051
1260