class Gem::Specification

Specification 类包含 gem 的信息。通常在 .gemspec 文件或 Rakefile 中定义,如下所示

Gem::Specification.new do |s|
  s.name        = 'example'
  s.version     = '0.1.0'
  s.licenses    = ['MIT']
  s.summary     = "This is an example!"
  s.description = "Much longer explanation of the example!"
  s.authors     = ["Ruby Coder"]
  s.email       = '[email protected]'
  s.files       = ["lib/example.rb"]
  s.homepage    = 'https://rubygems.org.cn/gems/example'
  s.metadata    = { "source_code_uri" => "https://github.com/example/example" }
end

从 RubyGems 2.0 开始,Specification 可以保存任意元数据。有关添加到规范的元数据项的格式和大小限制,请参阅 metadata

常量

NONEXISTENT_SPECIFICATION_VERSION

未指定版本(即 RubyGems 0.7 或更早版本)的规范的版本号。

公共实例方法

removed_method_calls() 点击切换源代码
# File rubygems/specification.rb, line 189
def removed_method_calls
  @removed_method_calls ||= []
end

可选 gemspec 属性

↑ 顶部

常量

LATEST_RUBY_WITHOUT_PATCH_VERSIONS

属性

bindir[RW]

gem 中可执行脚本的路径。通常为 'exe'

用法

spec.bindir = 'exe'
cert_chain[RW]

用于签署此 gem 的证书链。有关详细信息,请参阅 Gem::Security

post_install_message[RW]

gem 安装后显示的消息。

用法

spec.post_install_message = "Thanks for installing!"
required_rubygems_version[R]

此 gem 需要的 RubyGems 版本

signing_key[RW]

用于签署此 gem 的密钥。有关详细信息,请参阅 Gem::Security

公共实例方法

add_dependency(gem, *requirements) 点击切换源代码

向此 gem 添加名为 gem 的运行时依赖项以及 requirements

用法

spec.add_dependency 'example', '~> 1.1', '>= 1.1.4'
# File rubygems/specification.rb, line 548
def add_dependency(gem, *requirements)
  if requirements.uniq.size != requirements.size
    warn "WARNING: duplicated #{gem} dependency #{requirements}"
  end

  add_dependency_with_type(gem, :runtime, requirements)
end
也别名为:add_runtime_dependency
add_development_dependency(gem, *requirements) 点击切换源代码

向此 gem 添加名为 gem 的开发依赖项以及 requirements

用法

spec.add_development_dependency 'example', '~> 1.1', '>= 1.1.4'

默认情况下不安装开发依赖项,并且在需要 gem 时不会激活。

# File rubygems/specification.rb, line 537
def add_development_dependency(gem, *requirements)
  add_dependency_with_type(gem, :development, requirements)
end
author=(o) 点击切换源代码

用于 authors 的单数(替代)写入器

用法

spec.author = 'John Jones'
# File rubygems/specification.rb, line 415
def author=(o)
  self.authors = [o]
end
executables() 点击切换源代码

gem 中包含的可执行文件。

例如,rake gem 将 rake 作为可执行文件。您不必指定完整路径(如 bin/rake);所有应用程序样式的文件都应在 bindir 中找到。这些文件必须是可执行的 Ruby 文件。使用 bash 或其他解释器的文件将不起作用。

包含的可执行文件只能是 ruby 脚本,而不能是其他语言的脚本或编译的二进制文件。

用法

spec.executables << 'rake'
# File rubygems/specification.rb, line 571
def executables
  @executables ||= []
end
extensions() 点击切换源代码

安装 gem 时要构建的扩展,特别是用于编译扩展的 extconf.rb 样式文件的路径。

这些文件将在安装 gem 时运行,导致 C(或其他)代码在用户的计算机上编译。

用法

spec.extensions << 'ext/rmagic/extconf.rb'

有关为 gem 编写扩展的信息,请参阅 Gem::Ext::Builder

# File rubygems/specification.rb, line 588
def extensions
  @extensions ||= []
end
extra_rdoc_files() 点击切换源代码

要添加到 RDoc 的额外文件,例如 README 或 doc/examples.txt

当用户选择为 gem 生成 RDoc 文档时(通常在安装时),所有库文件都会发送到 RDoc 进行处理。此选项允许您包含一些非代码文件,以获得更完整的文档集。

用法

spec.extra_rdoc_files = ['README', 'doc/user-guide.txt']
# File rubygems/specification.rb, line 604
def extra_rdoc_files
  @extra_rdoc_files ||= []
end
platform=(platform) 点击切换源代码

此 gem 运行的平台。

通常为 Gem::Platform::RUBY 或 Gem::Platform::CURRENT。

大多数 gem 包含纯 Ruby 代码;它们应简单地保留默认值。某些 gem 包含 C(或其他)代码,这些代码将被编译到 Ruby“扩展”中。除非代码仅在特定类型的系统上编译,否则 gem 应保留默认值。某些 gem 由预编译代码(“二进制 gem”)组成。尤其重要的是,它们应正确设置平台属性。一种快捷方式是将平台设置为 Gem::Platform::CURRENT,这将导致 gem 构建器将平台设置为正在执行构建的系统的适当值。

如果此属性设置为非默认值,则它将包含在构建 gem 时 gem 的文件名中,例如:nokogiri-1.6.0-x86-mingw32.gem

用法

spec.platform = Gem::Platform.local
# File rubygems/specification.rb, line 466
def platform=(platform)
  @original_platform = platform

  case platform
  when Gem::Platform::CURRENT then
    @new_platform = Gem::Platform.local
    @original_platform = @new_platform.to_s

  when Gem::Platform then
    @new_platform = platform

  # legacy constants
  when nil, Gem::Platform::RUBY then
    @new_platform = Gem::Platform::RUBY
  when "mswin32" then # was Gem::Platform::WIN32
    @new_platform = Gem::Platform.new "x86-mswin32"
  when "i586-linux" then # was Gem::Platform::LINUX_586
    @new_platform = Gem::Platform.new "x86-linux"
  when "powerpc-darwin" then # was Gem::Platform::DARWIN
    @new_platform = Gem::Platform.new "ppc-darwin"
  else
    @new_platform = Gem::Platform.new platform
  end

  @platform = @new_platform.to_s

  invalidate_memoized_attributes
end
rdoc_options() 点击切换源代码

指定生成 API 文档时要使用的 rdoc 选项。

用法

spec.rdoc_options << '--title' << 'Rake -- Ruby Make' <<
  '--main' << 'README' <<
  '--line-numbers'
# File rubygems/specification.rb, line 634
def rdoc_options
  @rdoc_options ||= []
end
require_paths=(val) 点击切换源代码

当此 gem 被激活时,要添加到 $LOAD_PATH 的 gem 中的路径。如果您有扩展,则无需将 "ext" 添加到 require 路径,扩展构建过程会将扩展文件复制到“lib”中。

默认值为 "lib"

用法

# If all library files are in the root directory...
spec.require_paths = ['.']
# File rubygems/specification.rb, line 512
def require_paths=(val)
  @require_paths = Array(val)
end
required_ruby_version=(req) 点击切换源代码

此 gem 需要的 Ruby 版本。可以将 ruby 版本指定到补丁级别

$ ruby -v -e 'p Gem.ruby_version'
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]
#<Gem::Version "2.0.0.247">

也可以指定预发布版本。

用法

# This gem will work with 1.8.6 or greater...
spec.required_ruby_version = '>= 1.8.6'

# Only with final releases of major version 2 where minor version is at least 3
spec.required_ruby_version = '~> 2.3'

# Only prereleases or final releases after 2.6.0.preview2
spec.required_ruby_version = '> 2.6.0.preview2'

# This gem will work with 2.3.0 or greater, including major version 3, but lesser than 4.0.0
spec.required_ruby_version = '>= 2.3', '< 4'
# File rubygems/specification.rb, line 664
def required_ruby_version=(req)
  @required_ruby_version = Gem::Requirement.create req

  @required_ruby_version.requirements.map! do |op, v|
    if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4
      [op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))]
    else
      [op, v]
    end
  end
end
required_rubygems_version=(req) 点击切换源代码

此 gem 需要的 RubyGems 版本

# File rubygems/specification.rb, line 679
def required_rubygems_version=(req)
  @required_rubygems_version = Gem::Requirement.create req
end
requirements() 点击切换源代码

列出此 gem 要工作必须满足的外部(对于 RubyGems)要求。这只是提供给用户的信息。

用法

spec.requirements << 'libmagick, v6.0'
spec.requirements << 'A good graphics card'
# File rubygems/specification.rb, line 692
def requirements
  @requirements ||= []
end

只读属性

↑ 顶部

属性

rubygems_version[RW]

用于创建此 gem 的 RubyGems 版本。

公共实例方法

extensions_dir() 点击切换源代码

此 gem 安装其扩展的路径。

# File rubygems/specification.rb, line 719
def extensions_dir
  @extensions_dir ||= super
end

推荐的 gemspec 属性

↑ 顶部

属性

description[R]

对此 gem 的详细描述

描述应比摘要更详细,但不要过长。建议使用几段,不包含示例或格式。

用法

spec.description = <<~EOF
  Rake is a Make-like program implemented in Ruby. Tasks and
  dependencies are specified in standard Ruby syntax.
EOF
email[RW]

此 gem 的联系电子邮件地址(或多个地址)

用法

spec.email = '[email protected]'
spec.email = ['[email protected]', '[email protected]']
homepage[RW]

此 gem 主页的 URL

用法

spec.homepage = 'https://github.com/ruby/rake'
metadata[RW]

元数据保存此 gem 的额外数据,这些数据可能对其他使用者有用,并且可以由 gem 作者设置。

元数据项具有以下限制

  • 元数据必须是 Hash 对象

  • 所有键和值都必须是字符串

  • 键的最大长度为 128 个字节,值最大长度为 1024 个字节

  • 所有字符串都必须是 UTF-8,不允许使用二进制数据

您可以使用元数据来指定指向 gem 的主页、代码库、文档、wiki、邮件列表、问题跟踪器和更改日志的链接。

s.metadata = {
  "bug_tracker_uri"   => "https://example.com/user/bestgemever/issues",
  "changelog_uri"     => "https://example.com/user/bestgemever/CHANGELOG.md",
  "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
  "homepage_uri"      => "https://bestgemever.example.io",
  "mailing_list_uri"  => "https://groups.example.com/bestgemever",
  "source_code_uri"   => "https://example.com/user/bestgemever",
  "wiki_uri"          => "https://example.com/user/bestgemever/wiki",
  "funding_uri"       => "https://example.com/donate"
}

这些链接将用于 rubygems.org 上 gem 的页面,并且必须通过针对以下正则表达式的验证。

%r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}
required_ruby_version[R]

此 gem 需要的 Ruby 版本

用法

spec.required_ruby_version = '>= 2.7.0'

公共实例方法

license=(o) 点击切换源代码

此 gem 的许可证。

许可证长度不得超过 64 个字符。

这应该只是你的许可证的名称。当您构建 gem 时,许可证的完整文本应该在 gem 的内部(顶层)。

最简单的方法是为许可证指定标准的 SPDX ID spdx.org/licenses/。理想情况下,您应该选择一个经过 OSI(开放源代码促进会) opensource.org/licenses/ 批准的许可证。

最常用的 OSI 批准的许可证是 MIT 和 Apache-2.0。 GitHub 还提供了一个许可证选择器,网址是 choosealicense.com/。

您还可以将自定义许可证文件与您的 gemspec 一起使用,并指定 LicenseRef-<idstring>,其中 idstring 是包含许可证文本的文件的名称。

您应该为您的 gem 指定许可证,以便人们知道他们被允许如何使用它以及您对其施加的任何限制。不指定许可证意味着保留所有权利;其他人无权将代码用于任何目的。

您可以使用 licenses= 设置多个许可证

用法

spec.license = 'MIT'
# File rubygems/specification.rb, line 351
def license=(o)
  self.licenses = [o]
end
licenses=(licenses) 点击切换源代码

库的许可证。

每个许可证必须是一个短名称,不超过 64 个字符。

这应该只是你的许可证的名称。当您构建 gem 时,许可证的完整文本应该在 gem 的内部。

有关更多讨论,请参阅 license=

用法

spec.licenses = ['MIT', 'GPL-2.0']
# File rubygems/specification.rb, line 368
def licenses=(licenses)
  @licenses = Array licenses
end

必需的 gemspec 属性

↑ 顶部

属性

name[RW]

此 gem 的名称。

用法

spec.name = 'rake'
summary[R]

此 gem 描述的简短摘要。显示在 gem list -d 中。

description 应该比摘要更详细。

用法

spec.summary = "This is a small summary of my gem"
version[R]

此 gem 的版本。

版本字符串可以包含数字和句点,例如 1.0.0。如果版本中包含字母,例如 1.0.0.pre,则 gem 是“预发布”gem。

用法

spec.version = '0.4.1'

公共实例方法

authors=(value) 点击切换源代码

此 gem 的作者列表。

或者,可以通过将字符串赋值给 spec.author 来指定单个作者

用法

spec.authors = ['John Jones', 'Mary Smith']
# File rubygems/specification.rb, line 270
def authors=(value)
  @authors = Array(value).flatten.grep(String)
end
files() 点击切换源代码

此 gem 中包含的文件。您不能附加到此访问器,您必须为其赋值。

仅将可以要求的文件添加到此列表中,而不是目录等。

构建 gem 时,目录会自动从此列表中删除,其他非文件会导致错误。

用法

require 'rake'
spec.files = FileList['lib/**/*.rb',
                      'bin/*',
                      '[A-Z]*'].to_a

# or without Rake...
spec.files = Dir['lib/**/*.rb'] + Dir['bin/*']
spec.files += Dir['[A-Z]*']
spec.files.reject! { |fn| fn.include? "CVS" }
# File rubygems/specification.rb, line 250
def files
  # DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks)
  # DOC: Why isn't it normal? Why does it suck? How can we fix this?
  @files = [@files,
            @test_files,
            add_bindir(@executables),
            @extra_rdoc_files,
            @extensions].flatten.compact.uniq.sort
end

Specification 内部结构

↑ 顶部

属性

activated[RW]

当此 gemspec 已激活时为 True。此属性不会持久化。

activated?[RW]

当此 gemspec 已激活时为 True。此属性不会持久化。

default_executable[W]

设置此 gem 的默认可执行文件。

已弃用:您现在必须将可执行文件名指定给 Gem.bin_path

specification_version[RW]

此 gemspec 的 Gem::Specification 版本。

不要设置此项,它会在打包 gem 时自动设置。

公共类方法

_load(str) 点击切换源代码

加载自定义 marshal 格式,根据需要重新初始化默认值

# File rubygems/specification.rb, line 1245
def self._load(str)
  Gem.load_yaml
  Gem.load_safe_marshal

  yaml_set = false
  retry_count = 0

  array = begin
    Gem::SafeMarshal.safe_load str
  rescue ArgumentError => e
    # Avoid an infinite retry loop when the argument error has nothing to do
    # with the classes not being defined.
    # 1 retry each allowed in case all 3 of
    # - YAML
    # - YAML::Syck::DefaultKey
    # - YAML::PrivateType
    # need to be defined
    raise if retry_count >= 3

    #
    # Some very old marshaled specs included references to `YAML::PrivateType`
    # and `YAML::Syck::DefaultKey` constants due to bugs in the old emitter
    # that generated them. Workaround the issue by defining the necessary
    # constants and retrying.
    #
    message = e.message
    raise unless message.include?("YAML::")

    unless Object.const_defined?(:YAML)
      Object.const_set "YAML", Psych
      yaml_set = true
    end

    if message.include?("YAML::Syck::")
      YAML.const_set "Syck", YAML unless YAML.const_defined?(:Syck)

      YAML::Syck.const_set "DefaultKey", Class.new if message.include?("YAML::Syck::DefaultKey") && !YAML::Syck.const_defined?(:DefaultKey)
    elsif message.include?("YAML::PrivateType") && !YAML.const_defined?(:PrivateType)
      YAML.const_set "PrivateType", Class.new
    end

    retry_count += 1
    retry
  ensure
    Object.__send__(:remove_const, "YAML") if yaml_set
  end

  spec = Gem::Specification.new
  spec.instance_variable_set :@specification_version, array[1]

  current_version = CURRENT_SPECIFICATION_VERSION

  field_count = if spec.specification_version > current_version
    spec.instance_variable_set :@specification_version,
                               current_version
    MARSHAL_FIELDS[current_version]
  else
    MARSHAL_FIELDS[spec.specification_version]
  end

  if array.size < field_count
    raise TypeError, "invalid Gem::Specification format #{array.inspect}"
  end

  spec.instance_variable_set :@rubygems_version,          array[0]
  # spec version
  spec.instance_variable_set :@name,                      array[2]
  spec.instance_variable_set :@version,                   array[3]
  spec.date =                                             array[4]
  spec.instance_variable_set :@summary,                   array[5]
  spec.instance_variable_set :@required_ruby_version,     array[6]
  spec.instance_variable_set :@required_rubygems_version, array[7]
  spec.platform =                                         array[8]
  spec.instance_variable_set :@dependencies,              array[9]
  # offset due to rubyforge_project removal
  spec.instance_variable_set :@email,                     array[11]
  spec.instance_variable_set :@authors,                   array[12]
  spec.instance_variable_set :@description,               array[13]
  spec.instance_variable_set :@homepage,                  array[14]
  spec.instance_variable_set :@has_rdoc,                  array[15]
  spec.instance_variable_set :@licenses,                  [array[17]]
  spec.instance_variable_set :@metadata,                  array[18]
  spec.instance_variable_set :@loaded,                    false
  spec.instance_variable_set :@activated,                 false

  spec
end
add_spec(spec) 点击切换源代码

spec 添加到已知的规范中,保持集合的正确排序。

# File rubygems/specification.rb, line 858
def self.add_spec(spec)
  specification_record.add_spec(spec)
end
all() 点击切换源代码

返回所有规范。不建议使用此方法。您可能希望改用 Enumerable 方法之一。

# File rubygems/specification.rb, line 873
def self.all
  warn "NOTE: Specification.all called from #{caller(1, 1).first}" unless
    Gem::Deprecate.skip
  _all
end
all=(specs) 点击切换源代码

将已知的规范设置为 specs

# File rubygems/specification.rb, line 882
def self.all=(specs)
  specification_record.all = specs
end
all_names() 点击切换源代码

按排序顺序返回所有规范的全名。

# File rubygems/specification.rb, line 889
def self.all_names
  specification_record.all_names
end
array_attributes() 点击切换源代码

返回所有面向数组的实例变量的列表。

# File rubygems/specification.rb, line 898
def self.array_attributes
  @@array_attributes.dup
end
attribute_names() 点击切换源代码

返回所有实例变量的列表。

# File rubygems/specification.rb, line 907
def self.attribute_names
  @@attributes.dup
end
default_stubs(pattern = "*.gemspec") 点击切换源代码

为默认 gem 返回 Gem::StubSpecification

# File rubygems/specification.rb, line 805
def self.default_stubs(pattern = "*.gemspec")
  base_dir = Gem.default_dir
  gems_dir = File.join base_dir, "gems"
  gemspec_stubs_in(Gem.default_specifications_dir, pattern) do |path|
    Gem::StubSpecification.default_gemspec_stub(path, base_dir, gems_dir)
  end
end
dirs() 点击切换源代码

返回 Specification 用于查找规范的目录。

# File rubygems/specification.rb, line 914
def self.dirs
  @@dirs ||= Gem::SpecificationRecord.dirs_from(gem_path)
end
dirs=(dirs) 点击切换源代码

设置 Specification 用于查找规范的目录。设置此项将重置已知规范的列表。

# File rubygems/specification.rb, line 922
def self.dirs=(dirs)
  reset

  @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs))
end
each(&block) 点击切换源代码

枚举每个已知的规范。请参阅 ::dirs=::add_spec 以设置规范列表。

# File rubygems/specification.rb, line 934
def self.each(&block)
  specification_record.each(&block)
end
find_active_stub_by_path(path) 点击切换源代码

在已激活的规范中,返回包含与 path 匹配的文件的最佳规范。

# File rubygems/specification.rb, line 987
def self.find_active_stub_by_path(path)
  specification_record.find_active_stub_by_path(path)
end
find_all_by_full_name(full_name) 点击切换源代码

返回每个具有给定 full_name 的规范

# File rubygems/specification.rb, line 948
def self.find_all_by_full_name(full_name)
  stubs.select {|s| s.full_name == full_name }.map(&:to_spec)
end
find_all_by_name(name, *requirements) 点击切换源代码

返回每个匹配 name 和可选 requirements 的规范。

# File rubygems/specification.rb, line 941
def self.find_all_by_name(name, *requirements)
  specification_record.find_all_by_name(name, *requirements)
end
find_by_full_name(full_name) 点击切换源代码

查找与 full_name 匹配的最佳规范。

# File rubygems/specification.rb, line 964
def self.find_by_full_name(full_name)
  stubs.find {|s| s.full_name == full_name }&.to_spec
end
find_by_name(name, *requirements) 点击切换源代码

查找与 namerequirements 匹配的最佳规范。如果依赖项未解析为有效规范,则引发异常。

# File rubygems/specification.rb, line 956
def self.find_by_name(name, *requirements)
  requirements = Gem::Requirement.default if requirements.empty?

  Gem::Dependency.new(name, *requirements).to_spec
end
find_by_path(path) 点击切换源代码

返回包含与 path 匹配的文件的最佳规范。

# File rubygems/specification.rb, line 971
def self.find_by_path(path)
  specification_record.find_by_path(path)
end
find_in_unresolved(path) 点击切换源代码

返回包含与 path 匹配的文件的当前未解析规范。

# File rubygems/specification.rb, line 994
def self.find_in_unresolved(path)
  unresolved_specs.find_all {|spec| spec.contains_requirable_file? path }
end
find_in_unresolved_tree(path) 点击切换源代码

搜索所有未解析的依赖项和子依赖项,并返回包含与 path 匹配的文件的规范。

# File rubygems/specification.rb, line 1002
def self.find_in_unresolved_tree(path)
  unresolved_specs.each do |spec|
    spec.traverse do |_from_spec, _dep, to_spec, trail|
      if to_spec.has_conflicts? || to_spec.conficts_when_loaded_with?(trail)
        :next
      else
        return trail.reverse if to_spec.contains_requirable_file? path
      end
    end
  end

  []
end
find_inactive_by_path(path) 点击切换源代码

在未激活的规范中,返回包含与 path 匹配的文件的最佳规范。

# File rubygems/specification.rb, line 979
def self.find_inactive_by_path(path)
  specification_record.find_inactive_by_path(path)
end
from_yaml(input) 点击切换源代码

YAML 文件的特殊加载器。当从 YAML 文件加载 Specification 对象时,它会绕过正常的 Ruby 对象初始化例程(initialize)。此方法弥补了这一点,并处理不同时期的 gem。

input 可以是 YAML.load() 接受的任何内容:String 或 IO。

# File rubygems/specification.rb, line 1029
def self.from_yaml(input)
  Gem.load_yaml

  input = normalize_yaml_input input
  spec = Gem::SafeYAML.safe_load input

  if spec && spec.class == FalseClass
    raise Gem::EndOfYAMLException
  end

  unless Gem::Specification === spec
    raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
  end

  spec.specification_version ||= NONEXISTENT_SPECIFICATION_VERSION
  spec.reset_nil_attributes_to_default
  spec.flatten_require_paths

  spec
end
latest_spec_for(name) 点击切换源代码

返回 gem name 的最新安装规范。

# File rubygems/specification.rb, line 1061
def self.latest_spec_for(name)
  specification_record.latest_spec_for(name)
end
latest_specs(prerelease = false) 点击切换源代码

返回最新的规范,如果 prerelease 为 true,则可以选择包括预发布规范。

# File rubygems/specification.rb, line 1054
def self.latest_specs(prerelease = false)
  specification_record.latest_specs(prerelease)
end
load(file) 点击切换源代码

file 加载 Ruby 格式的 gemspec。

# File rubygems/specification.rb, line 1082
def self.load(file)
  return unless file

  spec = @load_cache_mutex.synchronize { @load_cache[file] }
  return spec if spec

  return unless File.file?(file)

  code = Gem.open_file(file, "r:UTF-8:-", &:read)

  begin
    spec = eval code, binding, file

    if Gem::Specification === spec
      spec.loaded_from = File.expand_path file.to_s
      @load_cache_mutex.synchronize do
        prev = @load_cache[file]
        if prev
          spec = prev
        else
          @load_cache[file] = spec
        end
      end
      return spec
    end

    warn "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
  rescue SignalException, SystemExit
    raise
  rescue SyntaxError, StandardError => e
    warn "Invalid gemspec in [#{file}]: #{e}"
  end

  nil
end
load_defaults() 点击切换源代码

加载默认规范。它应该只调用一次。

# File rubygems/specification.rb, line 846
def self.load_defaults
  each_spec([Gem.default_specifications_dir]) do |spec|
    # #load returns nil if the spec is bad, so we just ignore
    # it at this stage
    Gem.register_default_spec(spec)
  end
end
new(name = nil, version = nil) { |self| ... } 点击切换源代码

Specification 构造函数。将默认值分配给属性,并为了进一步初始化而 yield 自身。可以选择性地采用 nameversion

调用超类方法 Gem::BasicSpecification::new
# File rubygems/specification.rb, line 1986
def initialize(name = nil, version = nil)
  super()
  @gems_dir              = nil
  @base_dir              = nil
  @loaded = false
  @activated = false
  @loaded_from = nil
  @original_platform = nil
  @installed_by_version = nil

  set_nil_attributes_to_nil
  set_not_nil_attributes_to_default_values

  @new_platform = Gem::Platform::RUBY

  self.name = name if name
  self.version = version if version

  if (platform = Gem.platforms.last) && platform != Gem::Platform::RUBY && platform != Gem::Platform.local
    self.platform = platform
  end

  yield self if block_given?
end
non_nil_attributes() 点击切换源代码

Specification 必须非空的属性

# File rubygems/specification.rb, line 1121
def self.non_nil_attributes
  @@non_nil_attributes.dup
end
normalize_yaml_input(input) 点击切换源代码

确保 YAML 规范使用破折号正确格式化

# File rubygems/specification.rb, line 1128
def self.normalize_yaml_input(input)
  result = input.respond_to?(:read) ? input.read : input
  result = "--- " + result unless result.start_with?("--- ")
  result = result.dup
  result.gsub!(/ !!null \n/, " \n")
  # date: 2011-04-26 00:00:00.000000000Z
  # date: 2011-04-26 00:00:00.000000000 Z
  result.gsub!(/^(date: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+?)Z/, '\1 Z')
  result
end
outdated() 点击切换源代码

返回所有过时的本地 gem 名称的列表。此方法很重,因为它必须从服务器获取规范。

如果要检索最新的远程版本,请使用 outdated_and_latest_version

# File rubygems/specification.rb, line 1146
def self.outdated
  outdated_and_latest_version.map {|local, _| local.name }
end
outdated_and_latest_version() { |local_spec, latest_remote| ... } 点击切换源代码

枚举过时的本地 gem,产生本地规范和最新的远程版本。

此方法可能需要一些时间才能返回,因为它必须根据服务器的索引检查每个本地 gem。

# File rubygems/specification.rb, line 1157
def self.outdated_and_latest_version
  return enum_for __method__ unless block_given?

  # TODO: maybe we should switch to rubygems' version service?
  fetcher = Gem::SpecFetcher.fetcher

  latest_specs(true).each do |local_spec|
    dependency =
      Gem::Dependency.new local_spec.name, ">= #{local_spec.version}"

    remotes, = fetcher.search_for_dependency dependency
    remotes  = remotes.map {|n, _| n.version }

    latest_remote = remotes.sort.last

    yield [local_spec, latest_remote] if
      latest_remote && local_spec.version < latest_remote
  end

  nil
end
remove_spec(spec) 点击切换源代码

从已知规范中删除 spec

# File rubygems/specification.rb, line 865
def self.remove_spec(spec)
  specification_record.remove_spec(spec)
end
required_attribute?(name) 点击切换源码

name 是必需属性吗?

# File rubygems/specification.rb, line 1182
def self.required_attribute?(name)
  @@required_attributes.include? name.to_sym
end
required_attributes() 点击切换源码

必需的规范属性

# File rubygems/specification.rb, line 1189
def self.required_attributes
  @@required_attributes.dup
end
reset() 点击切换源码

重置已知规范的列表,运行在 Gem 中注册的预重置和后重置钩子。

# File rubygems/specification.rb, line 1197
def self.reset
  @@dirs = nil
  Gem.pre_reset_hooks.each(&:call)
  @specification_record = nil
  clear_load_cache

  unless unresolved_deps.empty?
    unresolved = unresolved_deps.filter_map do |name, dep|
      matching_versions = find_all_by_name(name)
      next if dep.latest_version? && matching_versions.any?(&:default_gem?)

      [dep, matching_versions.uniq(&:full_name)]
    end.to_h

    unless unresolved.empty?
      warn "WARN: Unresolved or ambiguous specs during Gem::Specification.reset:"
      unresolved.each do |dep, versions|
        warn "      #{dep}"

        unless versions.empty?
          warn "      Available/installed versions of this gem:"
          versions.each {|s| warn "      - #{s.version}" }
        end
      end
      warn "WARN: Clearing out unresolved specs. Try 'gem cleanup <gem>'"
      warn "Please report a bug if this causes problems."
    end

    unresolved_deps.clear
  end
  Gem.post_reset_hooks.each(&:call)
end
specification_record() 点击切换源码

跟踪所有当前已知的规范

# File rubygems/specification.rb, line 1233
def self.specification_record
  @specification_record ||= Gem::SpecificationRecord.new(dirs)
end
stubs() 点击切换源码

为每个已安装的 gem 返回一个 Gem::StubSpecification

# File rubygems/specification.rb, line 798
def self.stubs
  specification_record.stubs
end
stubs_for(name) 点击切换源码

为名为 name 的已安装 gem 返回一个 Gem::StubSpecification,仅返回与 Gem.platforms 匹配的存根

# File rubygems/specification.rb, line 817
def self.stubs_for(name)
  specification_record.stubs_for(name)
end
unresolved_deps() 点击切换源码

文档:此方法需要文档化或标记为 nodoc

# File rubygems/specification.rb, line 1238
def self.unresolved_deps
  @unresolved_deps ||= Hash.new {|h, n| h[n] = Gem::Dependency.new n }
end

私有类方法

unresolved_specs() 点击切换源码
# File rubygems/specification.rb, line 1016
def self.unresolved_specs
  unresolved_deps.values.flat_map(&:to_specs)
end

公共实例方法

_dump(limit) 点击切换源码

仅转储关键实例变量。

# File rubygems/specification.rb, line 1350
def _dump(limit)
  Marshal.dump [
    @rubygems_version,
    @specification_version,
    @name,
    @version,
    date,
    @summary,
    @required_ruby_version,
    @required_rubygems_version,
    @original_platform,
    @dependencies,
    "", # rubyforge_project
    @email,
    @authors,
    @description,
    @homepage,
    true, # has_rdoc
    @new_platform,
    @licenses,
    @metadata,
  ]
end
abbreviate() 点击切换源码

缩写规范以进行下载。缩写规范仅用于搜索、下载和相关活动,不需要特定于部署的信息(例如,文件列表)。因此,我们缩写规范,使其更小以便更快地下载。

# File rubygems/specification.rb, line 1441
def abbreviate
  self.files = []
  self.test_files = []
  self.rdoc_options = []
  self.extra_rdoc_files = []
  self.cert_chain = []
end
activate() 点击切换源码

激活此规范,将其注册为已加载的规范并将其 lib 路径添加到 $LOAD_PATH。如果规范已激活,则返回 true;如果先前已激活,则返回 false。如果在激活时出现冲突,则会引发异常。

# File rubygems/specification.rb, line 1380
def activate
  other = Gem.loaded_specs[name]
  if other
    check_version_conflict other
    return false
  end

  raise_if_conflicts

  activate_dependencies
  add_self_to_load_path

  Gem.loaded_specs[name] = self
  @activated = true
  @loaded = true

  true
end
activate_dependencies() 点击切换源码

激活此规范所有明确解析的运行时依赖项。将任何不明确的依赖项添加到未解析的列表中,以便稍后根据需要进行解析。

# File rubygems/specification.rb, line 1404
def activate_dependencies
  unresolved = Gem::Specification.unresolved_deps

  runtime_dependencies.each do |spec_dep|
    if loaded = Gem.loaded_specs[spec_dep.name]
      next if spec_dep.matches_spec? loaded

      msg = "can't satisfy '#{spec_dep}', already activated '#{loaded.full_name}'"
      e = Gem::LoadError.new msg
      e.name = spec_dep.name

      raise e
    end

    begin
      specs = spec_dep.to_specs.uniq(&:full_name)
    rescue Gem::MissingSpecError => e
      raise Gem::MissingSpecError.new(e.name, e.requirement, "at: #{spec_file}")
    end

    if specs.size == 1
      specs.first.activate
    else
      name = spec_dep.name
      unresolved[name] = unresolved[name].merge spec_dep
    end
  end

  unresolved.delete self.name
end
add_bindir(executables) 点击切换源码

返回一个数组,其中 bindir 附加到 executables 列表中的每个可执行文件

# File rubygems/specification.rb, line 1477
def add_bindir(executables)
  return nil if executables.nil?

  if @bindir
    Array(executables).map {|e| File.join(@bindir, e) }
  else
    executables
  end
rescue StandardError
  nil
end
add_runtime_dependency(gem, *requirements)
别名为:add_dependency
add_self_to_load_path() 点击切换源码

将此规范的 require 路径添加到 LOAD_PATH 中的正确位置。

# File rubygems/specification.rb, line 1516
def add_self_to_load_path
  return if default_gem?

  paths = full_require_paths

  Gem.add_to_load_path(*paths)
end
author() 点击切换源码

authors 的单数读取器。返回列表中的第一个作者

# File rubygems/specification.rb, line 1527
def author
  (val = authors) && val.first
end
authors() 点击切换源码

编写此 gem 的作者姓名列表。

spec.authors = ['Chad Fowler', 'Jim Weirich', 'Rich Kilmer']
# File rubygems/specification.rb, line 1536
def authors
  @authors ||= []
end
base_dir() 点击切换源码
# File rubygems/specification.rb, line 2040
def base_dir
  return Gem.dir unless loaded_from
  @base_dir ||= if default_gem?
    File.dirname File.dirname File.dirname loaded_from
  else
    File.dirname File.dirname loaded_from
  end
end
bin_dir() 点击切换源码

返回已安装 gem 的 bin 目录的完整路径。

注意:不要将其与 bindir 混淆,bindir 只是 “bin”,而不是完整路径。

# File rubygems/specification.rb, line 1546
def bin_dir
  @bin_dir ||= File.join gem_dir, bindir
end
bin_file(name) 点击切换源码

返回此 gem 中名为 name 的可执行文件的完整路径。

# File rubygems/specification.rb, line 1553
def bin_file(name)
  File.join bin_dir, name
end
build_args() 点击切换源码

返回用于安装 gem 的 build_args

# File rubygems/specification.rb, line 1560
def build_args
  if File.exist? build_info_file
    build_info = File.readlines build_info_file
    build_info = build_info.map(&:strip)
    build_info.delete ""
    build_info
  else
    []
  end
end
build_info_dir() 点击切换源码

返回 build info 目录的完整路径

# File rubygems/specification.rb, line 1608
def build_info_dir
  File.join base_dir, "build_info"
end
build_info_file() 点击切换源码

返回包含安装 gem 时生成的构建信息的文件完整路径

# File rubygems/specification.rb, line 1616
def build_info_file
  File.join build_info_dir, "#{full_name}.info"
end
cache_dir() 点击切换源码

返回包含此规范缓存 gem 的缓存目录的完整路径。

# File rubygems/specification.rb, line 1624
def cache_dir
  @cache_dir ||= File.join base_dir, "cache"
end
cache_file() 点击切换源码

返回此规范缓存 gem 的完整路径。

# File rubygems/specification.rb, line 1631
def cache_file
  @cache_file ||= File.join cache_dir, "#{full_name}.gem"
end
conflicts() 点击切换源码

返回当前已加载规范的任何可能冲突。

# File rubygems/specification.rb, line 1638
def conflicts
  conflicts = {}
  runtime_dependencies.each do |dep|
    spec = Gem.loaded_specs[dep.name]
    if spec && !spec.satisfies_requirement?(dep)
      (conflicts[spec] ||= []) << dep
    end
  end
  env_req = Gem.env_requirement(name)
  (conflicts[self] ||= []) << env_req unless env_req.satisfied_by? version
  conflicts
end
date() 点击切换源码

此 gem 的创建日期。

如果将 SOURCE_DATE_EPOCH 设置为环境变量,则使用它来支持可重现的构建;否则,默认为当前的 UTC 日期。

有关 SOURCE_DATE_EPOCH 的详细信息:reproducible-builds.org/specs/source-date-epoch/

# File rubygems/specification.rb, line 1682
def date
  @date ||= Time.utc(*Gem.source_date_epoch.utc.to_a[3..5].reverse)
end
date=(date) 点击切换源码

此 gem 的创建日期

不要设置此项,它会在打包 gem 时自动设置。

# File rubygems/specification.rb, line 1702
def date=(date)
  # We want to end up with a Time object with one-day resolution.
  # This is the cleanest, most-readable, faster-than-using-Date
  # way to do it.
  @date = case date
          when String then
            if DateTimeFormat =~ date
              Time.utc($1.to_i, $2.to_i, $3.to_i)
            else
              raise(Gem::InvalidSpecificationException,
                    "invalid date format in specification: #{date.inspect}")
            end
          when Time, DateLike then
            Time.utc(date.year, date.month, date.day)
          else
            TODAY
  end
end
default_value(name) 点击切换源码

规范属性 name 的默认值

# File rubygems/specification.rb, line 1742
def default_value(name)
  @@default_value[name]
end
dependencies() 点击切换源码

此 gem 依赖的 Gem::Dependency 对象列表。

使用 add_dependencyadd_development_dependency 向 gem 添加依赖项。

# File rubygems/specification.rb, line 1752
def dependencies
  @dependencies ||= []
end
dependent_gems(check_dev=true) 点击切换源码

返回所有依赖此 gemspec 的 gem 列表。该列表的结构条目符合

[depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
# File rubygems/specification.rb, line 1762
def dependent_gems(check_dev=true)
  out = []
  Gem::Specification.each do |spec|
    deps = check_dev ? spec.dependencies : spec.runtime_dependencies
    deps.each do |dep|
      next unless satisfies_requirement?(dep)
      sats = []
      find_all_satisfiers(dep) do |sat|
        sats << sat
      end
      out << [spec, dep, sats]
    end
  end
  out
end
dependent_specs() 点击切换源码

返回与此规范的运行时依赖项匹配的所有规范。

# File rubygems/specification.rb, line 1781
def dependent_specs
  runtime_dependencies.flat_map(&:to_specs)
end
description=(str) 点击切换源码

此 gem 的详细描述。另请参见 summary

# File rubygems/specification.rb, line 1788
def description=(str)
  @description = str.to_s
end
development_dependencies() 点击切换源码

用于开发的依赖项列表

# File rubygems/specification.rb, line 1795
def development_dependencies
  dependencies.select {|d| d.type == :development }
end
doc_dir(type = nil) 点击切换源码

返回此规范文档目录的完整路径。如果给出了 type,它将附加到末尾。例如

spec.doc_dir      # => "/path/to/gem_repo/doc/a-1"

spec.doc_dir 'ri' # => "/path/to/gem_repo/doc/a-1/ri"
# File rubygems/specification.rb, line 1807
def doc_dir(type = nil)
  @doc_dir ||= File.join base_dir, "doc", full_name

  if type
    File.join @doc_dir, type
  else
    @doc_dir
  end
end
executable() 点击切换源码

executables 的单数访问器

# File rubygems/specification.rb, line 1837
def executable
  (val = executables) && val.first
end
executable=(o) 点击切换源码

executables 的单数访问器

# File rubygems/specification.rb, line 1844
def executable=(o)
  self.executables = [o]
end
executables=(value) 点击切换源码

将 executables 设置为 value,确保它是一个数组。

# File rubygems/specification.rb, line 1851
def executables=(value)
  @executables = Array(value)
end
extensions=(extensions) 点击切换源码

将 extensions 设置为 extensions,确保它是一个数组。

# File rubygems/specification.rb, line 1858
def extensions=(extensions)
  @extensions = Array extensions
end
extra_rdoc_files=(files) 点击切换源码

extra_rdoc_files 设置为 files,确保它是一个数组。

# File rubygems/specification.rb, line 1865
def extra_rdoc_files=(files)
  @extra_rdoc_files = Array files
end
file_name() 点击切换源码

gem 的默认(生成的)文件名。另请参见 spec_name

spec.file_name # => "example-1.0.gem"
# File rubygems/specification.rb, line 1874
def file_name
  "#{full_name}.gem"
end
files=(files) 点击切换源码

将 files 设置为 files,确保它是一个数组。

# File rubygems/specification.rb, line 1881
def files=(files)
  @files = Array files
end
for_cache() 点击切换源码

创建一个没有在运行时使用的大型 blob 的重复规范。

# File rubygems/specification.rb, line 1899
def for_cache
  spec = dup

  spec.files = nil
  spec.test_files = nil

  spec
end
full_name() 点击切换源码
# File rubygems/specification.rb, line 1908
def full_name
  @full_name ||= super
end
gems_dir() 点击切换源码
# File rubygems/specification.rb, line 1920
def gems_dir
  @gems_dir ||= File.join(base_dir, "gems")
end
has_conflicts?() 点击切换源码

如果当前已加载规范存在可能的冲突,则返回 true。

# File rubygems/specification.rb, line 1664
def has_conflicts?
  return true unless Gem.env_requirement(name).satisfied_by?(version)
  runtime_dependencies.any? do |dep|
    spec = Gem.loaded_specs[dep.name]
    spec && !spec.satisfies_requirement?(dep)
  end
rescue ArgumentError => e
  raise e, "#{name} #{version}: #{e.message}"
end
initialize_copy(other_spec) 点击切换源码

复制 other_spec 中的 Array 和 Gem::Requirement 属性,以免共享状态。

# File rubygems/specification.rb, line 2015
def initialize_copy(other_spec)
  self.class.array_attributes.each do |name|
    name = :"@#{name}"
    next unless other_spec.instance_variable_defined? name

    begin
      val = other_spec.instance_variable_get(name)
      if val
        instance_variable_set name, val.dup
      elsif Gem.configuration.really_verbose
        warn "WARNING: #{full_name} has an invalid nil value for #{name}"
      end
    rescue TypeError
      e = Gem::FormatException.new \
        "#{full_name} has an invalid value for #{name}"

      e.file_path = loaded_from
      raise e
    end
  end

  @required_ruby_version = other_spec.required_ruby_version.dup
  @required_rubygems_version = other_spec.required_rubygems_version.dup
end
keep_only_files_and_directories() 点击切换源码
# File rubygems/specification.rb, line 2579
def keep_only_files_and_directories
  @executables.delete_if      {|x| File.directory?(File.join(@bindir, x)) }
  @extensions.delete_if       {|x| File.directory?(x) && !File.symlink?(x) }
  @extra_rdoc_files.delete_if {|x| File.directory?(x) && !File.symlink?(x) }
  @files.delete_if            {|x| File.directory?(x) && !File.symlink?(x) }
  @test_files.delete_if       {|x| File.directory?(x) && !File.symlink?(x) }
end
lib_files() 点击切换源码

Gem 中 require_paths 下的文件

# File rubygems/specification.rb, line 2071
def lib_files
  @files.select do |file|
    require_paths.any? do |path|
      file.start_with? path
    end
  end
end
license() 点击切换源码

licenses 的单数访问器

# File rubygems/specification.rb, line 2082
def license
  licenses.first
end
licenses() 点击切换源码

用于设置许可证的复数访问器

有关详细信息,请参见 license=

# File rubygems/specification.rb, line 2091
def licenses
  @licenses ||= []
end
missing_extensions?() 点击切换源码

此规范是否缺少其扩展?当此项返回 true 时,您可能需要 build_extensions

# File rubygems/specification.rb, line 2128
def missing_extensions?
  return false if extensions.empty?
  return false if default_gem?
  return false if File.exist? gem_build_complete_path

  true
end
name_tuple() 点击切换源码

返回一个表示此 Specification 的 NameTuple

# File rubygems/specification.rb, line 2159
def name_tuple
  Gem::NameTuple.new name, version, original_platform
end
normalize() 点击切换源码

规范化文件列表,以便

  • 所有文件列表都删除重复项。

  • extra_rdoc_files 中引用的文件包含在软件包文件列表中。

# File rubygems/specification.rb, line 2142
def normalize
  if defined?(@extra_rdoc_files) && @extra_rdoc_files
    @extra_rdoc_files.uniq!
    @files ||= []
    @files.concat(@extra_rdoc_files)
  end

  @files            = @files.uniq if @files
  @extensions       = @extensions.uniq if @extensions
  @test_files       = @test_files.uniq if @test_files
  @executables      = @executables.uniq if @executables
  @extra_rdoc_files = @extra_rdoc_files.uniq if @extra_rdoc_files
end
platform() 点击切换源码

此 gem 运行的平台。有关详细信息,请参见 Gem::Platform

# File rubygems/specification.rb, line 2185
def platform
  @new_platform ||= Gem::Platform::RUBY # rubocop:disable Naming/MemoizedInstanceVariableName
end
rdoc_options=(options) 点击切换源码

rdoc_options 设置为 value,并确保它是一个数组。

# File rubygems/specification.rb, line 2251
def rdoc_options=(options)
  @rdoc_options = Array options
end
require_path() 点击以切换源代码

require_paths 的单数访问器

# File rubygems/specification.rb, line 2258
def require_path
  (val = require_paths) && val.first
end
require_path=(path) 点击以切换源代码

require_paths 的单数访问器

# File rubygems/specification.rb, line 2265
def require_path=(path)
  self.require_paths = Array(path)
end
requirements=(req) 点击以切换源代码

将 requirements 设置为 req,并确保它是一个数组。

# File rubygems/specification.rb, line 2272
def requirements=(req)
  @requirements = Array req
end
reset_nil_attributes_to_default() 点击以切换源代码

将 nil 属性重置为它们的默认值,以使规范有效

# File rubygems/specification.rb, line 2637
def reset_nil_attributes_to_default
  nil_attributes = self.class.non_nil_attributes.find_all do |name|
    !instance_variable_defined?("@#{name}") || instance_variable_get("@#{name}").nil?
  end

  nil_attributes.each do |attribute|
    default = default_value attribute

    value = case default
            when Time, Numeric, Symbol, true, false, nil then default
            else default.dup
    end

    instance_variable_set "@#{attribute}", value
  end

  @installed_by_version ||= nil

  nil
end
ri_dir() 点击以切换源代码

返回此规范的 ri 目录的完整路径。

# File rubygems/specification.rb, line 2283
def ri_dir
  @ri_dir ||= File.join base_dir, "ri", full_name
end
runtime_dependencies() 点击以切换源代码

运行时将自动激活的依赖项列表。

# File rubygems/specification.rb, line 2316
def runtime_dependencies
  dependencies.select(&:runtime?)
end
sanitize() 点击以切换源代码

清理规范中的描述性字段。有时,非 ASCII 字符会损坏站点索引。非 ASCII 字符将被其 XML 实体等效项替换。

# File rubygems/specification.rb, line 1454
def sanitize
  self.summary              = sanitize_string(summary)
  self.description          = sanitize_string(description)
  self.post_install_message = sanitize_string(post_install_message)
  self.authors              = authors.collect {|a| sanitize_string(a) }
end
sanitize_string(string) 点击以切换源代码

清理单个字符串。

# File rubygems/specification.rb, line 1464
def sanitize_string(string)
  return string unless string

  # HACK: the #to_s is in here because RSpec has an Array of Arrays of
  # Strings for authors.  Need a way to disallow bad values on gemspec
  # generation.  (Probably won't happen.)
  string.to_s
end
satisfies_requirement?(dependency) 点击以切换源代码

检查此规范是否满足 dependency 的要求。

# File rubygems/specification.rb, line 2332
def satisfies_requirement?(dependency)
  @name == dependency.name &&
    dependency.requirement.satisfied_by?(@version)
end
sort_obj() 点击以切换源代码

返回一个可以用来在 sort_by 中对规范进行排序的对象。

# File rubygems/specification.rb, line 2340
def sort_obj
  [@name, @version, Gem::Platform.sort_priority(@new_platform)]
end
spec_dir() 点击以切换源代码

返回包含此规范的 gemspec 文件的目录的完整路径。例如:/usr/local/lib/ruby/gems/1.8/specifications

# File rubygems/specification.rb, line 2355
def spec_dir
  @spec_dir ||= File.join base_dir, "specifications"
end
spec_file() 点击以切换源代码

返回此规范的 gemspec 文件的完整路径。例如:/usr/local/lib/ruby/gems/1.8/specifications/mygem-1.0.gemspec

# File rubygems/specification.rb, line 2363
def spec_file
  @spec_file ||= File.join spec_dir, "#{full_name}.gemspec"
end
spec_name() 点击以切换源代码

gemspec 的默认名称。另请参见 file_name

spec.spec_name # => "example-1.0.gemspec"
# File rubygems/specification.rb, line 2372
def spec_name
  "#{full_name}.gemspec"
end
stubbed?() 点击以切换源代码
# File rubygems/specification.rb, line 2616
def stubbed?
  false
end
summary=(str) 点击以切换源代码

此 gem 的描述的简短摘要。

# File rubygems/specification.rb, line 2379
def summary=(str)
  @summary = str.to_s.strip.
    gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") # so. weird.
end
to_ruby() 点击以切换源代码

返回此规范的 Ruby 代码表示形式,以便可以对其进行 eval 并稍后重建相同的规范。仍具有默认值的属性将被省略。

# File rubygems/specification.rb, line 2422
def to_ruby
  result = []
  result << "# -*- encoding: utf-8 -*-"
  result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
  result << "#{Gem::StubSpecification::PREFIX}#{extensions.join "\0"}" unless
    extensions.empty?
  result << nil
  result << "Gem::Specification.new do |s|"

  result << "  s.name = #{ruby_code name}"
  result << "  s.version = #{ruby_code version}"
  unless platform.nil? || platform == Gem::Platform::RUBY
    result << "  s.platform = #{ruby_code original_platform}"
  end
  result << ""
  result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="

  if metadata && !metadata.empty?
    result << "  s.metadata = #{ruby_code metadata} if s.respond_to? :metadata="
  end
  result << "  s.require_paths = #{ruby_code raw_require_paths}"

  handled = [
    :dependencies,
    :name,
    :platform,
    :require_paths,
    :required_rubygems_version,
    :specification_version,
    :version,
    :has_rdoc,
    :default_executable,
    :metadata,
    :signing_key,
  ]

  @@attributes.each do |attr_name|
    next if handled.include? attr_name
    current_value = send(attr_name)
    if current_value != default_value(attr_name) || self.class.required_attribute?(attr_name)
      result << "  s.#{attr_name} = #{ruby_code current_value}"
    end
  end

  if String === signing_key
    result << "  s.signing_key = #{ruby_code signing_key}"
  end

  if @installed_by_version
    result << nil
    result << "  s.installed_by_version = #{ruby_code Gem::VERSION}"
  end

  unless dependencies.empty?
    result << nil
    result << "  s.specification_version = #{specification_version}"
    result << nil

    dependencies.each do |dep|
      dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
      result << "  s.add_#{dep.type}_dependency(%q<#{dep.name}>.freeze, #{ruby_code dep.requirements_list})"
    end
  end

  result << "end"
  result << nil

  result.join "\n"
end
to_ruby_for_cache() 点击以切换源代码

返回此规范的 Ruby 轻量级代码表示形式,仅用于索引。

请参阅 to_ruby

# File rubygems/specification.rb, line 2498
def to_ruby_for_cache
  for_cache.to_ruby
end
to_spec() 点击以切换源代码

返回 self

# File rubygems/specification.rb, line 2509
def to_spec
  self
end
traverse(trail = [], visited = {}, &block) 点击以切换源代码

递归遍历此规范的依赖项,为每次跳跃执行 block

# File rubygems/specification.rb, line 2540
def traverse(trail = [], visited = {}, &block)
  trail.push(self)
  begin
    runtime_dependencies.each do |dep|
      dep.matching_specs(true).each do |dep_spec|
        next if visited.key?(dep_spec)
        visited[dep_spec] = true
        trail.push(dep_spec)
        begin
          result = block[self, dep, dep_spec, trail]
        ensure
          trail.pop
        end
        next if result == :next
        spec_name = dep_spec.name
        dep_spec.traverse(trail, visited, &block) unless
          trail.any? {|s| s.name == spec_name }
      end
    end
  ensure
    trail.pop
  end
end
validate(packaging = true, strict = false) 点击以切换源代码

检查规范是否包含所有必需的字段,并进行非常基本的健全性检查。

如果规范未通过检查,则引发 InvalidSpecificationException。

# File rubygems/specification.rb, line 2571
def validate(packaging = true, strict = false)
  normalize

  validation_policy = Gem::SpecificationPolicy.new(self)
  validation_policy.packaging = packaging
  validation_policy.validate(strict)
end
validate_dependencies() 点击以切换源代码
# File rubygems/specification.rb, line 2596
def validate_dependencies
  Gem::SpecificationPolicy.new(self).validate_dependencies
end
validate_for_resolution() 点击以切换源代码
# File rubygems/specification.rb, line 2587
def validate_for_resolution
  Gem::SpecificationPolicy.new(self).validate_for_resolution
end
validate_metadata() 点击以切换源代码
# File rubygems/specification.rb, line 2591
def validate_metadata
  Gem::SpecificationPolicy.new(self).validate_metadata
end
validate_permissions() 点击以切换源代码
# File rubygems/specification.rb, line 2601
def validate_permissions
  Gem::SpecificationPolicy.new(self).validate_permissions
end
version=(version) 点击以切换源代码

将版本设置为 version

# File rubygems/specification.rb, line 2609
def version=(version)
  @version = Gem::Version.create(version)
  return if @version.nil?

  invalidate_memoized_attributes
end

私有实例方法

add_dependency_with_type(dependency, type, requirements) 点击以切换源代码

添加对 gem dependency 的依赖,其类型为 type,需要 requirements。当前有效类型为 :runtime:development

# File rubygems/specification.rb, line 1494
def add_dependency_with_type(dependency, type, requirements)
  requirements = if requirements.empty?
    Gem::Requirement.default
  else
    requirements.flatten
  end

  unless dependency.respond_to?(:name) &&
         dependency.respond_to?(:requirement)
    dependency = Gem::Dependency.new(dependency.to_s, requirements, type)
  end

  dependencies << dependency
end
find_all_satisfiers(dep) { |spec| ... } 点击以切换源代码

查找满足 dep 的所有 gem

# File rubygems/specification.rb, line 1888
def find_all_satisfiers(dep)
  Gem::Specification.each do |spec|
    yield spec if spec.satisfies_requirement? dep
  end
end
invalidate_memoized_attributes() 点击以切换源代码

使可错误生成、替换或错过文件(由于用于计算它们的某些属性的更改)的记忆实例变量过期。

# File rubygems/specification.rb, line 2053
def invalidate_memoized_attributes
  @full_name = nil
  @cache_file = nil
end
ruby_code(obj) 点击以切换源代码

返回包含给定对象的 Ruby 代码表示形式的字符串。

# File rubygems/specification.rb, line 2291
def ruby_code(obj)
  case obj
  when String             then obj.dump + ".freeze"
  when Array              then "[" + obj.map {|x| ruby_code x }.join(", ") + "]"
  when Hash               then
    seg = obj.keys.sort.map {|k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
    "{ #{seg.join(", ")} }"
  when Gem::Version       then ruby_code(obj.to_s)
  when DateLike           then obj.strftime("%Y-%m-%d").dump
  when Time               then obj.strftime("%Y-%m-%d").dump
  when Numeric            then obj.inspect
  when true, false, nil   then obj.inspect
  when Gem::Platform      then "Gem::Platform.new(#{ruby_code obj.to_a})"
  when Gem::Requirement   then
    list = obj.as_list
    "Gem::Requirement.new(#{ruby_code(list.size == 1 ? obj.to_s : list)})"
  else raise Gem::Exception, "ruby_code case not handled: #{obj.class}"
  end
end
same_attributes?(spec) 点击以切换源代码

如果此 gem 与 other 具有相同的属性,则为 True。

# File rubygems/specification.rb, line 2323
def same_attributes?(spec)
  @@attributes.all? {|name, _default| send(name) == spec.send(name) }
end