Geminstaller C0 Coverage Information - RCov

spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/specification.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/specification.rb 1502 760
78.03%
61.45%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 #--
2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3 # All rights reserved.
4 # See LICENSE.txt for permissions.
5 #++
6 
7 require 'rubygems/version'
8 require 'rubygems/requirement'
9 require 'rubygems/platform'
10 
11 # :stopdoc:
12 class Date; end # for ruby_code if date.rb wasn't required
13 # :startdoc:
14 
15 ##
16 # The Specification class contains the metadata for a Gem.  Typically
17 # defined in a .gemspec file or a Rakefile, and looks like this:
18 #
19 #   spec = Gem::Specification.new do |s|
20 #     s.name = 'example'
21 #     s.version = '1.0'
22 #     s.summary = 'Example gem specification'
23 #     ...
24 #   end
25 #
26 # For a great way to package gems, use Hoe.
27 
28 class Gem::Specification
29 
30   ##
31   # Allows deinstallation of gems with legacy platforms.
32 
33   attr_accessor :original_platform # :nodoc:
34 
35   ##
36   # The the version number of a specification that does not specify one
37   # (i.e. RubyGems 0.7 or earlier).
38 
39   NONEXISTENT_SPECIFICATION_VERSION = -1
40 
41   ##
42   # The specification version applied to any new Specification instances
43   # created.  This should be bumped whenever something in the spec format
44   # changes.
45   #--
46   # When updating this number, be sure to also update #to_ruby.
47   #
48   # NOTE RubyGems < 1.2 cannot load specification versions > 2.
49 
50   CURRENT_SPECIFICATION_VERSION = 3
51 
52   ##
53   # An informal list of changes to the specification.  The highest-valued
54   # key should be equal to the CURRENT_SPECIFICATION_VERSION.
55 
56   SPECIFICATION_VERSION_HISTORY = {
57     -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
58     1  => [
59       'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
60       '"test_file=x" is a shortcut for "test_files=[x]"'
61     ],
62     2  => [
63       'Added "required_rubygems_version"',
64       'Now forward-compatible with future versions',
65     ],
66     3 => [
67        'Added Fixnum validation to the specification_version'
68     ]
69   }
70 
71   # :stopdoc:
72   MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 }
73 
74   now = Time.at(Time.now.to_i)
75   TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
76   # :startdoc:
77 
78   ##
79   # Optional block used to gather newly defined instances.
80 
81   @@gather = nil
82 
83   ##
84   # List of attribute names: [:name, :version, ...]
85 
86   @@required_attributes = []
87 
88   ##
89   # List of _all_ attributes and default values:
90   #
91   #   [[:name, nil],
92   #    [:bindir, 'bin'],
93   #    ...]
94 
95   @@attributes = []
96 
97   @@nil_attributes = []
98   @@non_nil_attributes = [:@original_platform]
99 
100   ##
101   # List of array attributes
102 
103   @@array_attributes = []
104 
105   ##
106   # Map of attribute names to default values.
107 
108   @@default_value = {}
109 
110   ##
111   # Names of all specification attributes
112 
113   def self.attribute_names
114     @@attributes.map { |name, default| name }
115   end
116 
117   ##
118   # Default values for specification attributes
119 
120   def self.attribute_defaults
121     @@attributes.dup
122   end
123 
124   ##
125   # The default value for specification attribute +name+
126 
127   def self.default_value(name)
128     @@default_value[name]
129   end
130 
131   ##
132   # Required specification attributes
133 
134   def self.required_attributes
135     @@required_attributes.dup
136   end
137 
138   ##
139   # Is +name+ a required attribute?
140 
141   def self.required_attribute?(name)
142     @@required_attributes.include? name.to_sym
143   end
144 
145   ##
146   # Specification attributes that are arrays (appendable and so-forth)
147 
148   def self.array_attributes
149     @@array_attributes.dup
150   end
151 
152   ##
153   # Specifies the +name+ and +default+ for a specification attribute, and
154   # creates a reader and writer method like Module#attr_accessor.
155   #
156   # The reader method returns the default if the value hasn't been set.
157 
158   def self.attribute(name, default=nil)
159     ivar_name = "@#{name}".intern
160     if default.nil? then
161       @@nil_attributes << ivar_name
162     else
163       @@non_nil_attributes << [ivar_name, default]
164     end
165 
166     @@attributes << [name, default]
167     @@default_value[name] = default
168     attr_accessor(name)
169   end
170 
171   ##
172   # Same as :attribute, but ensures that values assigned to the attribute
173   # are array values by applying :to_a to the value.
174 
175   def self.array_attribute(name)
176     @@non_nil_attributes << ["@#{name}".intern, []]
177 
178     @@array_attributes << name
179     @@attributes << [name, []]
180     @@default_value[name] = []
181     code = %{
182       def #{name}
183         @#{name} ||= []
184       end
185       def #{name}=(value)
186         @#{name} = Array(value)
187       end
188     }
189 
190     module_eval code, __FILE__, __LINE__ - 9
191   end
192 
193   ##
194   # Same as attribute above, but also records this attribute as mandatory.
195 
196   def self.required_attribute(*args)
197     @@required_attributes << args.first
198     attribute(*args)
199   end
200 
201   ##
202   # Sometimes we don't want the world to use a setter method for a
203   # particular attribute.
204   #
205   # +read_only+ makes it private so we can still use it internally.
206 
207   def self.read_only(*names)
208     names.each do |name|
209       private "#{name}="
210     end
211   end
212 
213   # Shortcut for creating several attributes at once (each with a default
214   # value of +nil+).
215 
216   def self.attributes(*args)
217     args.each do |arg|
218       attribute(arg, nil)
219     end
220   end
221 
222   ##
223   # Some attributes require special behaviour when they are accessed.  This
224   # allows for that.
225 
226   def self.overwrite_accessor(name, &block)
227     remove_method name
228     define_method(name, &block)
229   end
230 
231   ##
232   # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
233   # whose value is expected to be an array).  This means just creating a
234   # helper method that takes a single value and appends it to the array.
235   # These are created for convenience, so that in a spec, one can write
236   #
237   #   s.require_path = 'mylib'
238   #
239   # instead of:
240   #
241   #   s.require_paths = ['mylib']
242   #
243   # That above convenience is available courtesy of:
244   #
245   #   attribute_alias_singular :require_path, :require_paths
246 
247   def self.attribute_alias_singular(singular, plural)
248     define_method("#{singular}=") { |val|
249       send("#{plural}=", [val])
250     }
251     define_method("#{singular}") {
252       val = send("#{plural}")
253       val.nil? ? nil : val.first
254     }
255   end
256 
257   ##
258   # Dump only crucial instance variables.
259   #--
260   # MAINTAIN ORDER!
261 
262   def _dump(limit)
263     Marshal.dump [
264       @rubygems_version,
265       @specification_version,
266       @name,
267       @version,
268       (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))),
269       @summary,
270       @required_ruby_version,
271       @required_rubygems_version,
272       @original_platform,
273       @dependencies,
274       @rubyforge_project,
275       @email,
276       @authors,
277       @description,
278       @homepage,
279       @has_rdoc,
280       @new_platform,
281       @licenses
282     ]
283   end
284 
285   ##
286   # Load custom marshal format, re-initializing defaults as needed
287 
288   def self._load(str)
289     array = Marshal.load str
290 
291     spec = Gem::Specification.new
292     spec.instance_variable_set :@specification_version, array[1]
293 
294     current_version = CURRENT_SPECIFICATION_VERSION
295 
296     field_count = if spec.specification_version > current_version then
297                     spec.instance_variable_set :@specification_version,
298                                                current_version
299                     MARSHAL_FIELDS[current_version]
300                   else
301                     MARSHAL_FIELDS[spec.specification_version]
302                   end
303 
304     if array.size < field_count then
305       raise TypeError, "invalid Gem::Specification format #{array.inspect}"
306     end
307 
308     spec.instance_variable_set :@rubygems_version,          array[0]
309     # spec version
310     spec.instance_variable_set :@name,                      array[2]
311     spec.instance_variable_set :@version,                   array[3]
312     spec.instance_variable_set :@date,                      array[4]
313     spec.instance_variable_set :@summary,                   array[5]
314     spec.instance_variable_set :@required_ruby_version,     array[6]
315     spec.instance_variable_set :@required_rubygems_version, array[7]
316     spec.instance_variable_set :@original_platform,         array[8]
317     spec.instance_variable_set :@dependencies,              array[9]
318     spec.instance_variable_set :@rubyforge_project,         array[10]
319     spec.instance_variable_set :@email,                     array[11]
320     spec.instance_variable_set :@authors,                   array[12]
321     spec.instance_variable_set :@description,               array[13]
322     spec.instance_variable_set :@homepage,                  array[14]
323     spec.instance_variable_set :@has_rdoc,                  array[15]
324     spec.instance_variable_set :@new_platform,              array[16]
325     spec.instance_variable_set :@platform,                  array[16].to_s
326     spec.instance_variable_set :@license,                   array[17]
327     spec.instance_variable_set :@loaded,                    false
328 
329     spec
330   end
331 
332   ##
333   # List of depedencies that will automatically be activated at runtime.
334 
335   def runtime_dependencies
336     dependencies.select { |d| d.type == :runtime || d.type == nil }
337   end
338 
339   ##
340   # List of dependencies that are used for development
341 
342   def development_dependencies
343     dependencies.select { |d| d.type == :development }
344   end
345 
346   def test_suite_file # :nodoc:
347     warn 'test_suite_file deprecated, use test_files'
348     test_files.first
349   end
350 
351   def test_suite_file=(val) # :nodoc:
352     warn 'test_suite_file= deprecated, use test_files='
353     @test_files = [] unless defined? @test_files
354     @test_files << val
355   end
356 
357   ##
358   # true when this gemspec has been loaded from a specifications directory.
359   # This attribute is not persisted.
360 
361   attr_accessor :loaded
362 
363   ##
364   # Path this gemspec was loaded from.  This attribute is not persisted.
365 
366   attr_accessor :loaded_from
367 
368   ##
369   # Returns an array with bindir attached to each executable in the
370   # executables list
371 
372   def add_bindir(executables)
373     return nil if executables.nil?
374 
375     if @bindir then
376       Array(executables).map { |e| File.join(@bindir, e) }
377     else
378       executables
379     end
380   rescue
381     return nil
382   end
383 
384   ##
385   # Files in the Gem under one of the require_paths
386 
387   def lib_files
388     @files.select do |file|
389       require_paths.any? do |path|
390         file.index(path) == 0
391       end
392     end
393   end
394 
395   ##
396   # True if this gem was loaded from disk
397 
398   alias :loaded? :loaded
399 
400   ##
401   # True if this gem has files in test_files
402 
403   def has_unit_tests?
404     not test_files.empty?
405   end
406 
407   # :stopdoc:
408   alias has_test_suite? has_unit_tests?
409   # :startdoc:
410 
411   ##
412   # Specification constructor.  Assigns the default values to the
413   # attributes and yields itself for further
414   # initialization. Optionally takes +name+ and +version+.
415 
416   def initialize name = nil, version = nil
417     @new_platform = nil
418     assign_defaults
419     @loaded = false
420     @loaded_from = nil
421 
422     self.name = name if name
423     self.version = version if version
424 
425     yield self if block_given?
426 
427     @@gather.call(self) if @@gather
428   end
429 
430   ##
431   # Duplicates array_attributes from +other_spec+ so state isn't shared.
432 
433   def initialize_copy(other_spec)
434     other_ivars = other_spec.instance_variables
435     other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9
436       other_ivars.any? { |ivar| String === ivar }
437 
438     self.class.array_attributes.each do |name|
439       name = :"@#{name}"
440       next unless other_ivars.include? name
441       instance_variable_set name, other_spec.instance_variable_get(name).dup
442     end
443   end
444 
445   ##
446   # Each attribute has a default value (possibly nil).  Here, we initialize
447   # all attributes to their default value.  This is done through the
448   # accessor methods, so special behaviours will be honored.  Furthermore,
449   # we take a _copy_ of the default so each specification instance has its
450   # own empty arrays, etc.
451 
452   def assign_defaults
453     @@nil_attributes.each do |name|
454       instance_variable_set name, nil
455     end
456 
457     @@non_nil_attributes.each do |name, default|
458       value = case default
459               when Time, Numeric, Symbol, true, false, nil then default
460               else default.dup
461               end
462 
463       instance_variable_set name, value
464     end
465 
466     # HACK
467     instance_variable_set :@new_platform, Gem::Platform::RUBY
468   end
469 
470   ##
471   # Special loader for YAML files.  When a Specification object is loaded
472   # from a YAML file, it bypasses the normal Ruby object initialization
473   # routine (#initialize).  This method makes up for that and deals with
474   # gems of different ages.
475   #
476   # 'input' can be anything that YAML.load() accepts: String or IO.
477 
478   def self.from_yaml(input)
479     input = normalize_yaml_input input
480     spec = YAML.load input
481 
482     if spec && spec.class == FalseClass then
483       raise Gem::EndOfYAMLException
484     end
485 
486     unless Gem::Specification === spec then
487       raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
488     end
489 
490     unless (spec.instance_variables.include? '@specification_version' or
491             spec.instance_variables.include? :@specification_version) and
492            spec.instance_variable_get :@specification_version
493       spec.instance_variable_set :@specification_version,
494                                  NONEXISTENT_SPECIFICATION_VERSION
495     end
496 
497     spec
498   end
499 
500   ##
501   # Loads ruby format gemspec from +filename+
502 
503   def self.load(filename)
504     gemspec = nil
505     raise "NESTED Specification.load calls not allowed!" if @@gather
506     @@gather = proc { |gs| gemspec = gs }
507     data = File.read filename
508     eval data, nil, filename
509     gemspec
510   ensure
511     @@gather = nil
512   end
513 
514   ##
515   # Make sure the YAML specification is properly formatted with dashes
516 
517   def self.normalize_yaml_input(input)
518     result = input.respond_to?(:read) ? input.read : input
519     result = "--- " + result unless result =~ /^--- /
520     result
521   end
522 
523   ##
524   # Sets the rubygems_version to the current RubyGems version
525 
526   def mark_version
527     @rubygems_version = Gem::VERSION
528   end
529 
530   ##
531   # Ignore unknown attributes while loading
532 
533   def method_missing(sym, *a, &b) # :nodoc:
534     if @specification_version > CURRENT_SPECIFICATION_VERSION and
535       sym.to_s =~ /=$/ then
536       warn "ignoring #{sym} loading #{full_name}" if $DEBUG
537     else
538       super
539     end
540   end
541 
542   ##
543   # Adds a development dependency named +gem+ with +requirements+ to this
544   # Gem.  For example:
545   #
546   #   spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
547   #
548   # Development dependencies aren't installed by default and aren't
549   # activated when a gem is required.
550 
551   def add_development_dependency(gem, *requirements)
552     add_dependency_with_type(gem, :development, *requirements)
553   end
554 
555   ##
556   # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
557   # For example:
558   #
559   #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
560 
561   def add_runtime_dependency(gem, *requirements)
562     add_dependency_with_type(gem, :runtime, *requirements)
563   end
564 
565   ##
566   # Adds a runtime dependency
567 
568   alias add_dependency add_runtime_dependency
569 
570   ##
571   # Returns the full name (name-version) of this Gem.  Platform information
572   # is included (name-version-platform) if it is specified and not the
573   # default Ruby platform.
574 
575   def full_name
576     if platform == Gem::Platform::RUBY or platform.nil? then
577       "#{@name}-#{@version}"
578     else
579       "#{@name}-#{@version}-#{platform}"
580     end
581   end
582 
583   ##
584   # Returns the full name (name-version) of this gemspec using the original
585   # platform.  For use with legacy gems.
586 
587   def original_name # :nodoc:
588     if platform == Gem::Platform::RUBY or platform.nil? then
589       "#{@name}-#{@version}"
590     else
591       "#{@name}-#{@version}-#{@original_platform}"
592     end
593   end
594 
595   ##
596   # The full path to the gem (install path + full name).
597 
598   def full_gem_path
599     path = File.join installation_path, 'gems', full_name
600     return path if File.directory? path
601     File.join installation_path, 'gems', original_name
602   end
603 
604   ##
605   # The default (generated) file name of the gem.  See also #spec_name.
606   #
607   #   spec.file_name # => "example-1.0.gem"
608 
609   def file_name
610     full_name + '.gem'
611   end
612 
613   ##
614   # The directory that this gem was installed into.
615 
616   def installation_path
617     unless @loaded_from then
618       raise Gem::Exception, "spec #{full_name} is not from an installed gem"
619     end
620 
621     File.expand_path File.dirname(File.dirname(@loaded_from))
622   end
623 
624   ##
625   # Checks if this specification meets the requirement of +dependency+.
626 
627   def satisfies_requirement?(dependency)
628     return @name == dependency.name &&
629       dependency.requirement.satisfied_by?(@version)
630   end
631 
632   ##
633   # Returns an object you can use to sort specifications in #sort_by.
634 
635   def sort_obj
636     [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1]
637   end
638 
639   ##
640   # The default name of the gemspec.  See also #file_name
641   #
642   #   spec.spec_name # => "example-1.0.gemspec"
643 
644   def spec_name
645     full_name + '.gemspec'
646   end
647 
648   def <=>(other) # :nodoc:
649     sort_obj <=> other.sort_obj
650   end
651 
652   ##
653   # Tests specs for equality (across all attributes).
654 
655   def ==(other) # :nodoc:
656     self.class === other && same_attributes?(other)
657   end
658 
659   alias eql? == # :nodoc:
660 
661   ##
662   # True if this gem has the same attributes as +other+.
663 
664   def same_attributes?(other)
665     @@attributes.each do |name, default|
666       return false unless self.send(name) == other.send(name)
667     end
668     true
669   end
670 
671   private :same_attributes?
672 
673   def hash # :nodoc:
674     @@attributes.inject(0) { |hash_code, (name, default_value)|
675       n = self.send(name).hash
676       hash_code + n
677     }
678   end
679 
680   def encode_with coder # :nodoc:
681     mark_version
682 
683     attributes = @@attributes.map { |name,| name.to_s }.sort
684     attributes = attributes - %w[name version platform]
685 
686     coder.add 'name', @name
687     coder.add 'version', @version
688     platform = case @original_platform
689                when nil, '' then
690                  'ruby'
691                when String then
692                  @original_platform
693                else
694                  @original_platform.to_s
695                end
696     coder.add 'platform', platform
697 
698     attributes.each do |name|
699       coder.add name, instance_variable_get("@#{name}")
700     end
701   end
702 
703   def to_yaml(opts = {}) # :nodoc:
704     return super if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
705 
706     yaml = YAML.quick_emit object_id, opts do |out|
707       out.map taguri, to_yaml_style do |map|
708         encode_with map
709       end
710     end
711   end
712 
713   def init_with coder # :nodoc:
714     yaml_initialize coder.tag, coder.map
715   end
716 
717   def yaml_initialize(tag, vals) # :nodoc:
718     vals.each do |ivar, val|
719       instance_variable_set "@#{ivar}", val
720     end
721 
722     @original_platform = @platform # for backwards compatibility
723     self.platform = Gem::Platform.new @platform
724   end
725 
726   ##
727   # Returns a Ruby code representation of this specification, such that it
728   # can be eval'ed and reconstruct the same specification later.  Attributes
729   # that still have their default values are omitted.
730 
731   def to_ruby
732     mark_version
733     result = []
734     result << "# -*- encoding: utf-8 -*-"
735     result << nil
736     result << "Gem::Specification.new do |s|"
737 
738     result << "  s.name = #{ruby_code name}"
739     result << "  s.version = #{ruby_code version}"
740     unless platform.nil? or platform == Gem::Platform::RUBY then
741       result << "  s.platform = #{ruby_code original_platform}"
742     end
743     result << ""
744     result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
745 
746     handled = [
747       :dependencies,
748       :name,
749       :platform,
750       :required_rubygems_version,
751       :specification_version,
752       :version,
753     ]
754 
755     attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
756 
757     attributes.each do |attr_name, default|
758       next if handled.include? attr_name
759       current_value = self.send(attr_name)
760       if current_value != default or
761          self.class.required_attribute? attr_name then
762         result << "  s.#{attr_name} = #{ruby_code current_value}"
763       end
764     end
765 
766     result << nil
767     result << "  if s.respond_to? :specification_version then"
768     result << "    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
769     result << "    s.specification_version = #{specification_version}"
770     result << nil
771 
772     result << "    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then"
773 
774     unless dependencies.empty? then
775       dependencies.each do |dep|
776         version_reqs_param = dep.requirements_list.inspect
777         dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
778         result << "      s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
779       end
780     end
781 
782     result << "    else"
783 
784     unless dependencies.empty? then
785       dependencies.each do |dep|
786         version_reqs_param = dep.requirements_list.inspect
787         result << "      s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
788       end
789     end
790 
791     result << '    end'
792 
793     result << "  else"
794       dependencies.each do |dep|
795         version_reqs_param = dep.requirements_list.inspect
796         result << "    s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
797       end
798     result << "  end"
799 
800     result << "end"
801     result << nil
802 
803     result.join "\n"
804   end
805 
806   ##
807   # Checks that the specification contains all required fields, and does a
808   # very basic sanity check.
809   #
810   # Raises InvalidSpecificationException if the spec does not pass the
811   # checks..
812 
813   def validate
814     extend Gem::UserInteraction
815     normalize
816 
817     if rubygems_version != Gem::VERSION then
818       raise Gem::InvalidSpecificationException,
819             "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
820     end
821 
822     @@required_attributes.each do |symbol|
823       unless self.send symbol then
824         raise Gem::InvalidSpecificationException,
825               "missing value for attribute #{symbol}"
826       end
827     end
828 
829     unless String === name then
830       raise Gem::InvalidSpecificationException,
831             "invalid value for attribute name: \"#{name.inspect}\""
832     end
833 
834     if require_paths.empty? then
835       raise Gem::InvalidSpecificationException,
836             'specification must have at least one require_path'
837     end
838 
839     @files.delete_if            do |file| File.directory? file end
840     @test_files.delete_if       do |file| File.directory? file end
841     @executables.delete_if      do |file|
842       File.directory? File.join(bindir, file)
843     end
844     @extra_rdoc_files.delete_if do |file| File.directory? file end
845     @extensions.delete_if       do |file| File.directory? file end
846 
847     non_files = files.select do |file|
848       !File.file? file
849     end
850 
851     unless non_files.empty? then
852       non_files = non_files.map { |file| file.inspect }
853       raise Gem::InvalidSpecificationException,
854             "[#{non_files.join ", "}] are not files"
855     end
856 
857     unless specification_version.is_a?(Fixnum)
858       raise Gem::InvalidSpecificationException,
859             'specification_version must be a Fixnum (did you mean version?)'
860     end
861 
862     case platform
863     when Gem::Platform, Gem::Platform::RUBY then # ok
864     else
865       raise Gem::InvalidSpecificationException,
866             "invalid platform #{platform.inspect}, see Gem::Platform"
867     end
868 
869     unless Array === authors and
870            authors.all? { |author| String === author } then
871       raise Gem::InvalidSpecificationException,
872             'authors must be Array of Strings'
873     end
874 
875     licenses.each { |license|
876       if license.length > 64
877         raise Gem::InvalidSpecificationException,
878           "each license must be 64 characters or less"
879       end
880     }
881 
882     # reject FIXME and TODO
883 
884     unless authors.grep(/FIXME|TODO/).empty? then
885       raise Gem::InvalidSpecificationException,
886             '"FIXME" or "TODO" is not an author'
887     end
888 
889     unless Array(email).grep(/FIXME|TODO/).empty? then
890       raise Gem::InvalidSpecificationException,
891             '"FIXME" or "TODO" is not an email address'
892     end
893 
894     if description =~ /FIXME|TODO/ then
895       raise Gem::InvalidSpecificationException,
896             '"FIXME" or "TODO" is not a description'
897     end
898 
899     if summary =~ /FIXME|TODO/ then
900       raise Gem::InvalidSpecificationException,
901             '"FIXME" or "TODO" is not a summary'
902     end
903 
904     if homepage and not homepage.empty? and
905        homepage !~ /\A[a-z][a-z\d+.-]*:/i then
906       raise Gem::InvalidSpecificationException,
907             "\"#{homepage}\" is not a URI"
908     end
909 
910     # Warnings
911 
912     %w[author description email homepage rubyforge_project summary].each do |attribute|
913       value = self.send attribute
914       alert_warning "no #{attribute} specified" if value.nil? or value.empty?
915     end
916 
917     if summary and not summary.empty? and description == summary then
918       alert_warning 'description and summary are identical'
919     end
920 
921     alert_warning "deprecated autorequire specified" if autorequire
922 
923     executables.each do |executable|
924       executable_path = File.join bindir, executable
925       shebang = File.read(executable_path, 2) == '#!'
926 
927       alert_warning "#{executable_path} is missing #! line" unless shebang
928     end
929 
930     true
931   end
932 
933   ##
934   # Normalize the list of files so that:
935   # * All file lists have redundancies removed.
936   # * Files referenced in the extra_rdoc_files are included in the package
937   #   file list.
938 
939   def normalize
940     if defined?(@extra_rdoc_files) and @extra_rdoc_files then
941       @extra_rdoc_files.uniq!
942       @files ||= []
943       @files.concat(@extra_rdoc_files)
944     end
945     @files.uniq! if @files
946   end
947 
948   ##
949   # Return a list of all gems that have a dependency on this gemspec.  The
950   # list is structured with entries that conform to:
951   #
952   #   [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
953 
954   def dependent_gems
955     out = []
956     Gem.source_index.each do |name,gem|
957       gem.dependencies.each do |dep|
958         if self.satisfies_requirement?(dep) then
959           sats = []
960           find_all_satisfiers(dep) do |sat|
961             sats << sat
962           end
963           out << [gem, dep, sats]
964         end
965       end
966     end
967     out
968   end
969 
970   def to_s # :nodoc:
971     "#<Gem::Specification name=#{@name} version=#{@version}>"
972   end
973 
974   def pretty_print(q) # :nodoc:
975     q.group 2, 'Gem::Specification.new do |s|', 'end' do
976       q.breakable
977 
978       attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
979 
980       attributes.each do |attr_name, default|
981         current_value = self.send attr_name
982         if current_value != default or
983            self.class.required_attribute? attr_name then
984 
985           q.text "s.#{attr_name} = "
986 
987           if attr_name == :date then
988             current_value = current_value.utc
989 
990             q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
991           else
992             q.pp current_value
993           end
994 
995           q.breakable
996         end
997       end
998     end
999   end
1000 
1001   ##
1002   # Adds a dependency on gem +dependency+ with type +type+ that requires
1003   # +requirements+.  Valid types are currently <tt>:runtime</tt> and
1004   # <tt>:development</tt>.
1005 
1006   def add_dependency_with_type(dependency, type, *requirements)
1007     requirements = if requirements.empty? then
1008                      Gem::Requirement.default
1009                    else
1010                      requirements.flatten
1011                    end
1012 
1013     unless dependency.respond_to?(:name) &&
1014       dependency.respond_to?(:version_requirements)
1015 
1016       dependency = Gem::Dependency.new(dependency, requirements, type)
1017     end
1018 
1019     dependencies << dependency
1020   end
1021 
1022   private :add_dependency_with_type
1023 
1024   ##
1025   # Finds all gems that satisfy +dep+
1026 
1027   def find_all_satisfiers(dep)
1028     Gem.source_index.each do |_, gem|
1029       yield gem if gem.satisfies_requirement? dep
1030     end
1031   end
1032 
1033   private :find_all_satisfiers
1034 
1035   ##
1036   # Return a string containing a Ruby code representation of the given
1037   # object.
1038 
1039   def ruby_code(obj)
1040     case obj
1041     when String            then '%q{' + obj + '}'
1042     when Array             then obj.inspect
1043     when Gem::Version      then obj.to_s.inspect
1044     when Date              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
1045     when Time              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
1046     when Numeric           then obj.inspect
1047     when true, false, nil  then obj.inspect
1048     when Gem::Platform     then "Gem::Platform.new(#{obj.to_a.inspect})"
1049     when Gem::Requirement  then "Gem::Requirement.new(#{obj.to_s.inspect})"
1050     else raise Gem::Exception, "ruby_code case not handled: #{obj.class}"
1051     end
1052   end
1053 
1054   private :ruby_code
1055 
1056   # :section: Required gemspec attributes
1057 
1058   ##
1059   # :attr_accessor: rubygems_version
1060   #
1061   # The version of RubyGems used to create this gem.
1062   #
1063   # Do not set this, it is set automatically when the gem is packaged.
1064 
1065   required_attribute :rubygems_version, Gem::VERSION
1066 
1067   ##
1068   # :attr_accessor: specification_version
1069   #
1070   # The Gem::Specification version of this gemspec.
1071   #
1072   # Do not set this, it is set automatically when the gem is packaged.
1073 
1074   required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
1075 
1076   ##
1077   # :attr_accessor: name
1078   #
1079   # This gem's name
1080 
1081   required_attribute :name
1082 
1083   ##
1084   # :attr_accessor: version
1085   #
1086   # This gem's version
1087 
1088   required_attribute :version
1089 
1090   ##
1091   # :attr_accessor: date
1092   #
1093   # The date this gem was created
1094   #
1095   # Do not set this, it is set automatically when the gem is packaged.
1096 
1097   required_attribute :date, TODAY
1098 
1099   ##
1100   # :attr_accessor: summary
1101   #
1102   # A short summary of this gem's description.  Displayed in `gem list -d`.
1103   #
1104   # The description should be more detailed than the summary.  For example,
1105   # you might wish to copy the entire README into the description.
1106   #
1107   # As of RubyGems 1.3.2 newlines are no longer stripped.
1108 
1109   required_attribute :summary
1110 
1111   ##
1112   # :attr_accessor: require_paths
1113   #
1114   # Paths in the gem to add to $LOAD_PATH when this gem is activated.
1115   #
1116   # The default 'lib' is typically sufficient.
1117 
1118   required_attribute :require_paths, ['lib']
1119 
1120   # :section: Optional gemspec attributes
1121 
1122   ##
1123   # :attr_accessor: email
1124   #
1125   # A contact email for this gem
1126   #
1127   # If you are providing multiple authors and multiple emails they should be
1128   # in the same order such that:
1129   #
1130   #   Hash[*spec.authors.zip(spec.emails).flatten]
1131   #
1132   # Gives a hash of author name to email address.
1133 
1134   attribute :email
1135 
1136   ##
1137   # :attr_accessor: homepage
1138   #
1139   # The URL of this gem's home page
1140 
1141   attribute :homepage
1142 
1143   ##
1144   # :attr_accessor: rubyforge_project
1145   #
1146   # The rubyforge project this gem lives under.  i.e. RubyGems'
1147   # rubyforge_project is "rubygems".
1148 
1149   attribute :rubyforge_project
1150 
1151   ##
1152   # :attr_accessor: description
1153   #
1154   # A long description of this gem
1155 
1156   attribute :description
1157 
1158   ##
1159   # :attr_accessor: autorequire
1160   #
1161   # Autorequire was used by old RubyGems to automatically require a file.
1162   # It no longer is supported.
1163 
1164   attribute :autorequire
1165 
1166   ##
1167   # :attr_accessor: default_executable
1168   #
1169   # The default executable for this gem.
1170   #
1171   # This is not used.
1172 
1173   attribute :default_executable
1174 
1175   ##
1176   # :attr_accessor: bindir
1177   #
1178   # The path in the gem for executable scripts
1179 
1180   attribute :bindir, 'bin'
1181 
1182   ##
1183   # :attr_accessor: has_rdoc
1184   #
1185   # Deprecated and ignored, defaults to true.
1186   #
1187   # Formerly used to indicate this gem was RDoc-capable.
1188 
1189   attribute :has_rdoc, true
1190 
1191   ##
1192   # True if this gem supports RDoc
1193 
1194   alias :has_rdoc? :has_rdoc
1195 
1196   ##
1197   # :attr_accessor: required_ruby_version
1198   #
1199   # The version of ruby required by this gem
1200 
1201   attribute :required_ruby_version, Gem::Requirement.default
1202 
1203   ##
1204   # :attr_accessor: required_rubygems_version
1205   #
1206   # The RubyGems version required by this gem
1207 
1208   attribute :required_rubygems_version, Gem::Requirement.default
1209 
1210   ##
1211   # :attr_accessor: platform
1212   #
1213   # The platform this gem runs on.  See Gem::Platform for details.
1214   #
1215   # Setting this to any value other than Gem::Platform::RUBY or
1216   # Gem::Platform::CURRENT is probably wrong.
1217 
1218   attribute :platform, Gem::Platform::RUBY
1219 
1220   ##
1221   # :attr_accessor: signing_key
1222   #
1223   # The key used to sign this gem.  See Gem::Security for details.
1224 
1225   attribute :signing_key, nil
1226 
1227   ##
1228   # :attr_accessor: cert_chain
1229   #
1230   # The certificate chain used to sign this gem.  See Gem::Security for
1231   # details.
1232 
1233   attribute :cert_chain, []
1234 
1235   ##
1236   # :attr_accessor: post_install_message
1237   #
1238   # A message that gets displayed after the gem is installed
1239 
1240   attribute :post_install_message, nil
1241 
1242   ##
1243   # :attr_accessor: authors
1244   #
1245   # The list of author names who wrote this gem.
1246   #
1247   # If you are providing multiple authors and multiple emails they should be
1248   # in the same order such that:
1249   #
1250   #   Hash[*spec.authors.zip(spec.emails).flatten]
1251   #
1252   # Gives a hash of author name to email address.
1253 
1254   array_attribute :authors
1255 
1256   ##
1257   # :attr_accessor: licenses
1258   #
1259   # The license(s) for the library.  Each license must be a short name, no
1260   # more than 64 characters.
1261 
1262   array_attribute :licenses
1263 
1264   ##
1265   # :attr_accessor: files
1266   #
1267   # Files included in this gem.  You cannot append to this accessor, you must
1268   # assign to it.
1269   #
1270   # Only add files you can require to this list, not directories, etc.
1271   #
1272   # Directories are automatically stripped from this list when building a gem,
1273   # other non-files cause an error.
1274 
1275   array_attribute :files
1276 
1277   ##
1278   # :attr_accessor: test_files
1279   #
1280   # Test files included in this gem.  You cannot append to this accessor, you
1281   # must assign to it.
1282 
1283   array_attribute :test_files
1284 
1285   ##
1286   # :attr_accessor: rdoc_options
1287   #
1288   # An ARGV style array of options to RDoc
1289 
1290   array_attribute :rdoc_options
1291 
1292   ##
1293   # :attr_accessor: extra_rdoc_files
1294   #
1295   # Extra files to add to RDoc such as README or doc/examples.txt
1296 
1297   array_attribute :extra_rdoc_files
1298 
1299   ##
1300   # :attr_accessor: executables
1301   #
1302   # Executables included in the gem.
1303 
1304   array_attribute :executables
1305 
1306   ##
1307   # :attr_accessor: extensions
1308   #
1309   # Extensions to build when installing the gem.  See
1310   # Gem::Installer#build_extensions for valid values.
1311 
1312   array_attribute :extensions
1313 
1314   ##
1315   # :attr_accessor: requirements
1316   #
1317   # An array or things required by this gem.  Not used by anything
1318   # presently.
1319 
1320   array_attribute :requirements
1321 
1322   ##
1323   # :attr_reader: dependencies
1324   #
1325   # A list of Gem::Dependency objects this gem depends on.
1326   #
1327   # Use #add_dependency or #add_development_dependency to add dependencies to
1328   # a gem.
1329 
1330   array_attribute :dependencies
1331 
1332   read_only :dependencies
1333 
1334   # :section: Aliased gemspec attributes
1335 
1336   ##
1337   # Singular accessor for #executables
1338 
1339   attribute_alias_singular :executable, :executables
1340 
1341   ##
1342   # Singular accessor for #authors
1343 
1344   attribute_alias_singular :author, :authors
1345 
1346   ##
1347   # Singular accessor for #licenses
1348 
1349   attribute_alias_singular :license, :licenses
1350 
1351   ##
1352   # Singular accessor for #require_paths
1353 
1354   attribute_alias_singular :require_path, :require_paths
1355 
1356   ##
1357   # Singular accessor for #test_files
1358 
1359   attribute_alias_singular :test_file, :test_files
1360 
1361   ##
1362   # has_rdoc is now ignored
1363 
1364   overwrite_accessor :has_rdoc do
1365     true
1366   end
1367 
1368   ##
1369   # has_rdoc is now ignored
1370 
1371   overwrite_accessor :has_rdoc= do |value|
1372     @has_rdoc = true
1373   end
1374 
1375   overwrite_accessor :version= do |version|
1376     @version = Gem::Version.create(version)
1377     self.required_rubygems_version = '> 1.3.1' if @version.prerelease?
1378     return @version
1379   end
1380 
1381   overwrite_accessor :platform do
1382     @new_platform
1383   end
1384 
1385   overwrite_accessor :platform= do |platform|
1386     if @original_platform.nil? or
1387        @original_platform == Gem::Platform::RUBY then
1388       @original_platform = platform
1389     end
1390 
1391     case platform
1392     when Gem::Platform::CURRENT then
1393       @new_platform = Gem::Platform.local
1394       @original_platform = @new_platform.to_s
1395 
1396     when Gem::Platform then
1397       @new_platform = platform
1398 
1399     # legacy constants
1400     when nil, Gem::Platform::RUBY then
1401       @new_platform = Gem::Platform::RUBY
1402     when 'mswin32' then # was Gem::Platform::WIN32
1403       @new_platform = Gem::Platform.new 'x86-mswin32'
1404     when 'i586-linux' then # was Gem::Platform::LINUX_586
1405       @new_platform = Gem::Platform.new 'x86-linux'
1406     when 'powerpc-darwin' then # was Gem::Platform::DARWIN
1407       @new_platform = Gem::Platform.new 'ppc-darwin'
1408     else
1409       @new_platform = Gem::Platform.new platform
1410     end
1411 
1412     @platform = @new_platform.to_s
1413 
1414     @new_platform
1415   end
1416 
1417   overwrite_accessor :required_ruby_version= do |value|
1418     @required_ruby_version = Gem::Requirement.create(value)
1419   end
1420 
1421   overwrite_accessor :required_rubygems_version= do |value|
1422     @required_rubygems_version = Gem::Requirement.create(value)
1423   end
1424 
1425   overwrite_accessor :date= do |date|
1426     # We want to end up with a Time object with one-day resolution.
1427     # This is the cleanest, most-readable, faster-than-using-Date
1428     # way to do it.
1429     case date
1430     when String then
1431       @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
1432                 Time.local($1.to_i, $2.to_i, $3.to_i)
1433               else
1434                 require 'time'
1435                 Time.parse date
1436               end
1437     when Time then
1438       @date = Time.local(date.year, date.month, date.day)
1439     when Date then
1440       @date = Time.local(date.year, date.month, date.day)
1441     else
1442       @date = TODAY
1443     end
1444   end
1445 
1446   overwrite_accessor :date do
1447     self.date = nil if @date.nil?  # HACK Sets the default value for date
1448     @date
1449   end
1450 
1451   overwrite_accessor :summary= do |str|
1452     @summary = if str then
1453                  str.strip.
1454                  gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
1455                  gsub(/\n[ \t]*/, " ")
1456                end
1457   end
1458 
1459   overwrite_accessor :description= do |str|
1460     @description = str.to_s
1461   end
1462 
1463   overwrite_accessor :default_executable do
1464     begin
1465       if defined?(@default_executable) and @default_executable
1466         result = @default_executable
1467       elsif @executables and @executables.size == 1
1468         result = Array(@executables).first
1469       else
1470         result = nil
1471       end
1472       result
1473     rescue
1474       nil
1475     end
1476   end
1477 
1478   overwrite_accessor :test_files do
1479     # Handle the possibility that we have @test_suite_file but not
1480     # @test_files.  This will happen when an old gem is loaded via
1481     # YAML.
1482     if defined? @test_suite_file then
1483       @test_files = [@test_suite_file].flatten
1484       @test_suite_file = nil
1485     end
1486     if defined?(@test_files) and @test_files then
1487       @test_files
1488     else
1489       @test_files = []
1490     end
1491   end
1492 
1493   overwrite_accessor :files do
1494     # DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks)
1495     @files = [@files,
1496               @test_files,
1497               add_bindir(@executables),
1498               @extra_rdoc_files,
1499               @extensions,
1500              ].flatten.uniq.compact
1501   end
1502 end

Generated on Mon May 10 23:40:28 -0700 2010 with rcov 0.9.8