Class Gem::Specification
In: lib/rubygems/specification.rb
Parent: Object

Gem::Specification

The Specification class contains the metadata for a Gem. Typically defined in a .gemspec file or a Rakefile, and looks like this:

  spec = Gem::Specification.new do |s|
    s.name = 'rfoo'
    s.version = '1.0'
    s.summary = 'Example gem specification'
    ...
  end

There are many gemspec attributes, and the best place to learn about them in the "Gemspec Reference" linked from the RubyGems wiki.

Constants

NONEXISTENT_SPECIFICATION_VERSION = -1   The the version number of a specification that does not specify one (i.e. RubyGems 0.7 or earlier).
CURRENT_SPECIFICATION_VERSION = 2   The specification version applied to any new Specification instances created. This should be bumped whenever something in the spec format changes.
SPECIFICATION_VERSION_HISTORY = { -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'], 1 => [ 'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"', '"test_file=x" is a shortcut for "test_files=[x]"'   An informal list of changes to the specification. The highest-valued key should be equal to the CURRENT_SPECIFICATION_VERSION.

External Aliases

loaded -> loaded?
  True if this gem was loaded from disk
== -> eql?

Attributes

loaded  [RW]  true when this gemspec has been loaded from a specifications directory. This attribute is not persisted.
loaded_from  [RW]  Path this gemspec was loaded from. This attribute is not persisted.

Public Class methods

Load custom marshal format, re-initializing defaults as needed

[Source]

     # File lib/rubygems/specification.rb, line 311
311:     def self._load(str)
312:       array = Marshal.load str
313: 
314:       spec = Gem::Specification.new
315:       spec.instance_variable_set :@specification_version, array[1]
316: 
317:       current_version = CURRENT_SPECIFICATION_VERSION
318: 
319:       field_count = if spec.specification_version > current_version then
320:                       spec.instance_variable_set :@specification_version,
321:                                                  current_version
322:                       MARSHAL_FIELDS[current_version]
323:                     else
324:                       MARSHAL_FIELDS[spec.specification_version]
325:                     end
326: 
327:       if array.size < field_count then
328:         raise TypeError, "invalid Gem::Specification format #{array.inspect}"
329:       end
330: 
331:       spec.instance_variable_set :@rubygems_version,          array[0]
332:       # spec version
333:       spec.instance_variable_set :@name,                      array[2]
334:       spec.instance_variable_set :@version,                   array[3]
335:       spec.instance_variable_set :@date,                      array[4]
336:       spec.instance_variable_set :@summary,                   array[5]
337:       spec.instance_variable_set :@required_ruby_version,     array[6]
338:       spec.instance_variable_set :@required_rubygems_version, array[7]
339:       spec.instance_variable_set :@original_platform,         array[8]
340:       spec.instance_variable_set :@dependencies,              array[9]
341:       spec.instance_variable_set :@rubyforge_project,         array[10]
342:       spec.instance_variable_set :@email,                     array[11]
343:       spec.instance_variable_set :@authors,                   array[12]
344:       spec.instance_variable_set :@description,               array[13]
345:       spec.instance_variable_set :@homepage,                  array[14]
346:       spec.instance_variable_set :@has_rdoc,                  array[15]
347:       spec.instance_variable_set :@new_platform,              array[16]
348:       spec.instance_variable_set :@platform,                  array[16].to_s
349:       spec.instance_variable_set :@loaded,                    false
350: 
351:       spec
352:     end

Same as :attribute, but ensures that values assigned to the attribute are array values by applying :to_a to the value.

[Source]

     # File lib/rubygems/specification.rb, line 199
199:     def self.array_attribute(name)
200:       @@non_nil_attributes << ["@#{name}".intern, []]
201: 
202:       @@array_attributes << name
203:       @@attributes << [name, []]
204:       @@default_value[name] = []
205:       code = %{
206:         def #{name}
207:           @#{name} ||= []
208:         end
209:         def #{name}=(value)
210:           @#{name} = Array(value)
211:         end
212:       }
213: 
214:       module_eval code, __FILE__, __LINE__ - 9
215:     end

Specification attributes that are arrays (appendable and so-forth)

[Source]

     # File lib/rubygems/specification.rb, line 164
164:     def self.array_attributes
165:       @@array_attributes.dup
166:     end

Specifies the name and default for a specification attribute, and creates a reader and writer method like Module#attr_accessor.

The reader method returns the default if the value hasn‘t been set.

[Source]

     # File lib/rubygems/specification.rb, line 182
182:     def self.attribute(name, default=nil)
183:       ivar_name = "@#{name}".intern
184:       if default.nil? then
185:         @@nil_attributes << ivar_name
186:       else
187:         @@non_nil_attributes << [ivar_name, default]
188:       end
189: 
190:       @@attributes << [name, default]
191:       @@default_value[name] = default
192:       attr_accessor(name)
193:     end

Defines a singular version of an existing plural attribute (i.e. one whose value is expected to be an array). This means just creating a helper method that takes a single value and appends it to the array. These are created for convenience, so that in a spec, one can write

  s.require_path = 'mylib'

instead of:

  s.require_paths = ['mylib']

That above convenience is available courtesy of:

  attribute_alias_singular :require_path, :require_paths

[Source]

     # File lib/rubygems/specification.rb, line 271
271:     def self.attribute_alias_singular(singular, plural)
272:       define_method("#{singular}=") { |val|
273:         send("#{plural}=", [val])
274:       }
275:       define_method("#{singular}") { 
276:         val = send("#{plural}")
277:         val.nil? ? nil : val.first
278:       }
279:     end

Default values for specification attributes

[Source]

     # File lib/rubygems/specification.rb, line 136
136:     def self.attribute_defaults
137:       @@attributes.dup
138:     end

Names of all specification attributes

[Source]

     # File lib/rubygems/specification.rb, line 129
129:     def self.attribute_names
130:       @@attributes.map { |name, default| name }
131:     end

Shortcut for creating several attributes at once (each with a default value of nil).

[Source]

     # File lib/rubygems/specification.rb, line 240
240:     def self.attributes(*args)
241:       args.each do |arg|
242:         attribute(arg, nil)
243:       end
244:     end

The default value for specification attribute name

[Source]

     # File lib/rubygems/specification.rb, line 143
143:     def self.default_value(name)
144:       @@default_value[name]
145:     end

Special loader for YAML files. When a Specification object is loaded from a YAML file, it bypasses the normal Ruby object initialization routine (initialize). This method makes up for that and deals with gems of different ages.

‘input’ can be anything that YAML.load() accepts: String or IO.

[Source]

     # File lib/rubygems/specification.rb, line 481
481:     def self.from_yaml(input)
482:       input = normalize_yaml_input input
483:       spec = YAML.load input
484: 
485:       if spec && spec.class == FalseClass then
486:         raise Gem::EndOfYAMLException
487:       end
488: 
489:       unless Gem::Specification === spec then
490:         raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
491:       end
492: 
493:       unless (spec.instance_variables.include? '@specification_version' or
494:               spec.instance_variables.include? :@specification_version) and
495:              spec.instance_variable_get :@specification_version
496:         spec.instance_variable_set :@specification_version, 
497:                                    NONEXISTENT_SPECIFICATION_VERSION
498:       end
499: 
500:       spec
501:     end

A list of Specification instances that have been defined in this Ruby instance.

[Source]

     # File lib/rubygems/specification.rb, line 172
172:     def self.list
173:       @@list
174:     end

Loads ruby format gemspec from filename

[Source]

     # File lib/rubygems/specification.rb, line 506
506:     def self.load(filename)
507:       gemspec = nil
508:       fail "NESTED Specification.load calls not allowed!" if @@gather
509:       @@gather = proc { |gs| gemspec = gs }
510:       data = File.read(filename)
511:       eval(data)
512:       gemspec
513:     ensure
514:       @@gather = nil
515:     end

Specification constructor. Assigns the default values to the attributes, adds this spec to the list of loaded specs (see Specification.list), and yields itself for further initialization.

[Source]

     # File lib/rubygems/specification.rb, line 436
436:     def initialize
437:       @new_platform = nil
438:       assign_defaults
439:       @loaded = false
440:       @loaded_from = nil
441:       @@list << self
442: 
443:       yield self if block_given?
444: 
445:       @@gather.call(self) if @@gather
446:     end

Make sure the YAML specification is properly formatted with dashes

[Source]

     # File lib/rubygems/specification.rb, line 520
520:     def self.normalize_yaml_input(input)
521:       result = input.respond_to?(:read) ? input.read : input
522:       result = "--- " + result unless result =~ /^--- /
523:       result
524:     end

Some attributes require special behaviour when they are accessed. This allows for that.

[Source]

     # File lib/rubygems/specification.rb, line 250
250:     def self.overwrite_accessor(name, &block)
251:       remove_method name
252:       define_method(name, &block)
253:     end

Sometimes we don‘t want the world to use a setter method for a particular attribute.

read_only makes it private so we can still use it internally.

[Source]

     # File lib/rubygems/specification.rb, line 231
231:     def self.read_only(*names)
232:       names.each do |name|
233:         private "#{name}="
234:       end
235:     end

Same as attribute above, but also records this attribute as mandatory.

[Source]

     # File lib/rubygems/specification.rb, line 220
220:     def self.required_attribute(*args)
221:       @@required_attributes << args.first
222:       attribute(*args)
223:     end

Is name a required attribute?

[Source]

     # File lib/rubygems/specification.rb, line 157
157:     def self.required_attribute?(name)
158:       @@required_attributes.include? name.to_sym
159:     end

Required specification attributes

[Source]

     # File lib/rubygems/specification.rb, line 150
150:     def self.required_attributes
151:       @@required_attributes.dup
152:     end

Public Instance methods

Dump only crucial instance variables.

[Source]

     # File lib/rubygems/specification.rb, line 286
286:     def _dump(limit)
287:       Marshal.dump [
288:         @rubygems_version,
289:         @specification_version,
290:         @name,
291:         @version,
292:         (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))),
293:         @summary,
294:         @required_ruby_version,
295:         @required_rubygems_version,
296:         @original_platform,
297:         @dependencies,
298:         @rubyforge_project,
299:         @email,
300:         @authors,
301:         @description,
302:         @homepage,
303:         @has_rdoc,
304:         @new_platform,
305:       ]
306:     end

Returns an array with bindir attached to each executable in the executables list

[Source]

     # File lib/rubygems/specification.rb, line 394
394:     def add_bindir(executables)
395:       return nil if executables.nil?
396: 
397:       if @bindir then
398:         Array(executables).map { |e| File.join(@bindir, e) }
399:       else
400:         executables
401:       end
402:     rescue
403:       return nil
404:     end
add_dependency(gem, *requirements)

Adds a development dependency named gem with requirements to this Gem. For example:

  spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'

Development dependencies aren‘t installed by default and aren‘t activated when a gem is required.

[Source]

     # File lib/rubygems/specification.rb, line 554
554:     def add_development_dependency(gem, *requirements)
555:       add_dependency_with_type(gem, :development, *requirements)
556:     end

Adds a runtime dependency named gem with requirements to this Gem. For example:

  spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'

[Source]

     # File lib/rubygems/specification.rb, line 564
564:     def add_runtime_dependency(gem, *requirements)
565:       add_dependency_with_type(gem, :runtime, *requirements)
566:     end

Each attribute has a default value (possibly nil). Here, we initialize all attributes to their default value. This is done through the accessor methods, so special behaviours will be honored. Furthermore, we take a copy of the default so each specification instance has its own empty arrays, etc.

[Source]

     # File lib/rubygems/specification.rb, line 455
455:     def assign_defaults
456:       @@nil_attributes.each do |name|
457:         instance_variable_set name, nil
458:       end
459: 
460:       @@non_nil_attributes.each do |name, default|
461:         value = case default
462:                 when Time, Numeric, Symbol, true, false, nil then default
463:                 else default.dup
464:                 end
465: 
466:         instance_variable_set name, value
467:       end
468: 
469:       # HACK
470:       instance_variable_set :@new_platform, Gem::Platform::RUBY
471:     end

Return a list of all gems that have a dependency on this gemspec. The list is structured with entries that conform to:

  [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]

[Source]

     # File lib/rubygems/specification.rb, line 872
872:     def dependent_gems
873:       out = []
874:       Gem.source_index.each do |name,gem|
875:         gem.dependencies.each do |dep|
876:           if self.satisfies_requirement?(dep) then
877:             sats = []
878:             find_all_satisfiers(dep) do |sat|
879:               sats << sat
880:             end
881:             out << [gem, dep, sats]
882:           end
883:         end
884:       end
885:       out
886:     end

List of dependencies that are used for development

[Source]

     # File lib/rubygems/specification.rb, line 364
364:     def development_dependencies
365:       dependencies.select { |d| d.type == :development }
366:     end

The default (generated) file name of the gem.

[Source]

     # File lib/rubygems/specification.rb, line 610
610:     def file_name
611:       full_name + ".gem"
612:     end

The full path to the gem (install path + full name).

[Source]

     # File lib/rubygems/specification.rb, line 601
601:     def full_gem_path
602:       path = File.join installation_path, 'gems', full_name
603:       return path if File.directory? path
604:       File.join installation_path, 'gems', original_name
605:     end

Returns the full name (name-version) of this Gem. Platform information is included (name-version-platform) if it is specified and not the default Ruby platform.

[Source]

     # File lib/rubygems/specification.rb, line 578
578:     def full_name
579:       if platform == Gem::Platform::RUBY or platform.nil? then
580:         "#{@name}-#{@version}"
581:       else
582:         "#{@name}-#{@version}-#{platform}"
583:       end
584:     end
has_test_suite?()

Alias for has_unit_tests?

True if this gem has files in test_files

[Source]

     # File lib/rubygems/specification.rb, line 425
425:     def has_unit_tests?
426:       not test_files.empty?
427:     end

The directory that this gem was installed into.

[Source]

     # File lib/rubygems/specification.rb, line 617
617:     def installation_path
618:       path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
619:       path = path.join File::SEPARATOR
620:       File.expand_path path
621:     end

Files in the Gem under one of the require_paths

[Source]

     # File lib/rubygems/specification.rb, line 409
409:     def lib_files
410:       @files.select do |file|
411:         require_paths.any? do |path|
412:           file.index(path) == 0
413:         end
414:       end
415:     end

Sets the rubygems_version to the current RubyGems version

[Source]

     # File lib/rubygems/specification.rb, line 529
529:     def mark_version
530:       @rubygems_version = RubyGemsVersion
531:     end

Normalize the list of files so that:

  • All file lists have redundancies removed.
  • Files referenced in the extra_rdoc_files are included in the package file list.

Also, the summary and description are converted to a normal format.

[Source]

     # File lib/rubygems/specification.rb, line 857
857:     def normalize
858:       if defined?(@extra_rdoc_files) and @extra_rdoc_files then
859:         @extra_rdoc_files.uniq!
860:         @files ||= []
861:         @files.concat(@extra_rdoc_files)
862:       end
863:       @files.uniq! if @files
864:     end

List of depedencies that will automatically be activated at runtime.

[Source]

     # File lib/rubygems/specification.rb, line 357
357:     def runtime_dependencies
358:       dependencies.select { |d| d.type == :runtime || d.type == nil }
359:     end

Checks if this specification meets the requirement of dependency.

[Source]

     # File lib/rubygems/specification.rb, line 626
626:     def satisfies_requirement?(dependency)
627:       return @name == dependency.name && 
628:         dependency.version_requirements.satisfied_by?(@version)
629:     end

Returns an object you can use to sort specifications in sort_by.

[Source]

     # File lib/rubygems/specification.rb, line 634
634:     def sort_obj
635:       [@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
636:     end

Returns a Ruby code representation of this specification, such that it can be eval‘ed and reconstruct the same specification later. Attributes that still have their default values are omitted.

[Source]

     # File lib/rubygems/specification.rb, line 711
711:     def to_ruby
712:       mark_version
713:       result = []
714:       result << "# -*- encoding: utf-8 -*-"
715:       result << nil
716:       result << "Gem::Specification.new do |s|"
717: 
718:       result << "  s.name = #{ruby_code name}"
719:       result << "  s.version = #{ruby_code version}"
720:       unless platform.nil? or platform == Gem::Platform::RUBY then
721:         result << "  s.platform = #{ruby_code original_platform}"
722:       end
723:       result << ""
724:       result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
725: 
726:       handled = [
727:         :dependencies,
728:         :name,
729:         :platform,
730:         :required_rubygems_version,
731:         :specification_version,
732:         :version,
733:       ]
734: 
735:       attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
736: 
737:       attributes.each do |attr_name, default|
738:         next if handled.include? attr_name
739:         current_value = self.send(attr_name)
740:         if current_value != default or
741:            self.class.required_attribute? attr_name then
742:           result << "  s.#{attr_name} = #{ruby_code current_value}"
743:         end
744:       end
745: 
746:       result << nil
747:       result << "  if s.respond_to? :specification_version then"
748:       result << "    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
749:       result << "    s.specification_version = #{specification_version}"
750:       result << nil
751: 
752:       result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
753: 
754:       unless dependencies.empty? then
755:         dependencies.each do |dep|
756:           version_reqs_param = dep.requirements_list.inspect
757:           dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
758:           result << "      s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
759:         end
760:       end
761: 
762:       result << "    else"
763: 
764:       unless dependencies.empty? then
765:         dependencies.each do |dep|
766:           version_reqs_param = dep.requirements_list.inspect
767:           result << "      s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
768:         end
769:       end
770: 
771:       result << '    end'
772: 
773:       result << "  else"
774:         dependencies.each do |dep|
775:           version_reqs_param = dep.requirements_list.inspect
776:           result << "    s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
777:         end
778:       result << "  end"
779: 
780:       result << "end"
781:       result << nil
782: 
783:       result.join "\n"
784:     end

[Source]

     # File lib/rubygems/specification.rb, line 888
888:     def to_s
889:       "#<Gem::Specification name=#{@name} version=#{@version}>"
890:     end

Checks that the specification contains all required fields, and does a very basic sanity check.

Raises InvalidSpecificationException if the spec does not pass the checks..

[Source]

     # File lib/rubygems/specification.rb, line 793
793:     def validate
794:       extend Gem::UserInteraction
795:       normalize
796: 
797:       if rubygems_version != RubyGemsVersion then
798:         raise Gem::InvalidSpecificationException,
799:               "expected RubyGems version #{RubyGemsVersion}, was #{rubygems_version}"
800:       end
801: 
802:       @@required_attributes.each do |symbol|
803:         unless self.send symbol then
804:           raise Gem::InvalidSpecificationException,
805:                 "missing value for attribute #{symbol}"
806:         end
807:       end 
808: 
809:       if require_paths.empty? then
810:         raise Gem::InvalidSpecificationException,
811:               "specification must have at least one require_path"
812:       end
813: 
814:       case platform
815:       when Gem::Platform, Platform::RUBY then # ok
816:       else
817:         raise Gem::InvalidSpecificationException,
818:               "invalid platform #{platform.inspect}, see Gem::Platform"
819:       end
820: 
821:       unless Array === authors and
822:              authors.all? { |author| String === author } then
823:         raise Gem::InvalidSpecificationException,
824:               'authors must be Array of Strings'
825:       end
826: 
827:       # Warnings
828: 
829:       %w[author email homepage rubyforge_project summary].each do |attribute|
830:         value = self.send attribute
831:         alert_warning "no #{attribute} specified" if value.nil? or value.empty?
832:       end
833: 
834:       alert_warning "RDoc will not be generated (has_rdoc == false)" unless
835:         has_rdoc
836: 
837:       alert_warning "deprecated autorequire specified" if autorequire
838: 
839:       executables.each do |executable|
840:         executable_path = File.join bindir, executable
841:         shebang = File.read(executable_path, 2) == '#!'
842: 
843:         alert_warning "#{executable_path} is missing #! line" unless shebang
844:       end
845: 
846:       true
847:     end

Required gemspec attributes

Optional gemspec attributes

External Aliases

has_rdoc -> has_rdoc?
  True if this gem supports RDoc