PageRenderTime 190ms CodeModel.GetById 81ms app.highlight 100ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/Ruby/lib/ruby/site_ruby/1.8/rubygems/specification.rb

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