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 或更早版本)的规范的版本号。
公共实例方法
# File rubygems/specification.rb, line 189 def removed_method_calls @removed_method_calls ||= [] end
可选 gemspec 属性
↑ 顶部常量
- LATEST_RUBY_WITHOUT_PATCH_VERSIONS
属性
gem 中可执行脚本的路径。通常为 'exe'
用法
spec.bindir = 'exe'
用于签署此 gem 的证书链。有关详细信息,请参阅 Gem::Security
。
gem 安装后显示的消息。
用法
spec.post_install_message = "Thanks for installing!"
此 gem 需要的 RubyGems 版本
用于签署此 gem 的密钥。有关详细信息,请参阅 Gem::Security
。
公共实例方法
向此 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
向此 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
gem 中包含的可执行文件。
例如,rake gem 将 rake 作为可执行文件。您不必指定完整路径(如 bin/rake);所有应用程序样式的文件都应在 bindir 中找到。这些文件必须是可执行的 Ruby 文件。使用 bash 或其他解释器的文件将不起作用。
包含的可执行文件只能是 ruby 脚本,而不能是其他语言的脚本或编译的二进制文件。
用法
spec.executables << 'rake'
# File rubygems/specification.rb, line 571 def executables @executables ||= [] end
安装 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
要添加到 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
此 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
指定生成 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
当此 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
此 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
此 gem 需要的 RubyGems 版本
# File rubygems/specification.rb, line 679 def required_rubygems_version=(req) @required_rubygems_version = Gem::Requirement.create req end
列出此 gem 要工作必须满足的外部(对于 RubyGems)要求。这只是提供给用户的信息。
用法
spec.requirements << 'libmagick, v6.0' spec.requirements << 'A good graphics card'
# File rubygems/specification.rb, line 692 def requirements @requirements ||= [] end
只读属性
↑ 顶部属性
用于创建此 gem 的 RubyGems 版本。
公共实例方法
此 gem 安装其扩展的路径。
# File rubygems/specification.rb, line 719 def extensions_dir @extensions_dir ||= super end
推荐的 gemspec 属性
↑ 顶部属性
对此 gem 的详细描述
描述应比摘要更详细,但不要过长。建议使用几段,不包含示例或格式。
用法
spec.description = <<~EOF Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. EOF
此 gem 的联系电子邮件地址(或多个地址)
用法
spec.email = '[email protected]' spec.email = ['[email protected]', '[email protected]']
此 gem 主页的 URL
用法
spec.homepage = 'https://github.com/ruby/rake'
元数据保存此 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}
此 gem 需要的 Ruby 版本
用法
spec.required_ruby_version = '>= 2.7.0'
公共实例方法
此 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
库的许可证。
每个许可证必须是一个短名称,不超过 64 个字符。
这应该只是你的许可证的名称。当您构建 gem 时,许可证的完整文本应该在 gem 的内部。
有关更多讨论,请参阅 license=
用法
spec.licenses = ['MIT', 'GPL-2.0']
# File rubygems/specification.rb, line 368 def licenses=(licenses) @licenses = Array licenses end
必需的 gemspec 属性
↑ 顶部属性
此 gem 的名称。
用法
spec.name = 'rake'
此 gem 描述的简短摘要。显示在 gem list -d
中。
description
应该比摘要更详细。
用法
spec.summary = "This is a small summary of my gem"
此 gem 的版本。
版本字符串可以包含数字和句点,例如 1.0.0
。如果版本中包含字母,例如 1.0.0.pre
,则 gem 是“预发布”gem。
用法
spec.version = '0.4.1'
公共实例方法
此 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 内部结构
↑ 顶部属性
当此 gemspec 已激活时为 True。此属性不会持久化。
当此 gemspec 已激活时为 True。此属性不会持久化。
设置此 gem 的默认可执行文件。
已弃用:您现在必须将可执行文件名指定给 Gem.bin_path
。
此 gemspec 的 Gem::Specification
版本。
不要设置此项,它会在打包 gem 时自动设置。
公共类方法
加载自定义 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
将 spec
添加到已知的规范中,保持集合的正确排序。
# File rubygems/specification.rb, line 858 def self.add_spec(spec) specification_record.add_spec(spec) end
返回所有规范。不建议使用此方法。您可能希望改用 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
将已知的规范设置为 specs
。
# File rubygems/specification.rb, line 882 def self.all=(specs) specification_record.all = specs end
按排序顺序返回所有规范的全名。
# File rubygems/specification.rb, line 889 def self.all_names specification_record.all_names end
返回所有面向数组的实例变量的列表。
# File rubygems/specification.rb, line 898 def self.array_attributes @@array_attributes.dup end
返回所有实例变量的列表。
# File rubygems/specification.rb, line 907 def self.attribute_names @@attributes.dup end
为默认 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
返回 Specification
用于查找规范的目录。
# File rubygems/specification.rb, line 914 def self.dirs @@dirs ||= Gem::SpecificationRecord.dirs_from(gem_path) end
设置 Specification
用于查找规范的目录。设置此项将重置已知规范的列表。
# File rubygems/specification.rb, line 922 def self.dirs=(dirs) reset @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs)) end
枚举每个已知的规范。请参阅 ::dirs=
和 ::add_spec
以设置规范列表。
# File rubygems/specification.rb, line 934 def self.each(&block) specification_record.each(&block) end
在已激活的规范中,返回包含与 path
匹配的文件的最佳规范。
# File rubygems/specification.rb, line 987 def self.find_active_stub_by_path(path) specification_record.find_active_stub_by_path(path) end
返回每个具有给定 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
返回每个匹配 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
查找与 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
查找与 name
和 requirements
匹配的最佳规范。如果依赖项未解析为有效规范,则引发异常。
# 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
返回包含与 path
匹配的文件的最佳规范。
# File rubygems/specification.rb, line 971 def self.find_by_path(path) specification_record.find_by_path(path) end
返回包含与 path
匹配的文件的当前未解析规范。
# File rubygems/specification.rb, line 994 def self.find_in_unresolved(path) unresolved_specs.find_all {|spec| spec.contains_requirable_file? path } end
搜索所有未解析的依赖项和子依赖项,并返回包含与 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
在未激活的规范中,返回包含与 path
匹配的文件的最佳规范。
# File rubygems/specification.rb, line 979 def self.find_inactive_by_path(path) specification_record.find_inactive_by_path(path) end
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
返回 gem name
的最新安装规范。
# File rubygems/specification.rb, line 1061 def self.latest_spec_for(name) specification_record.latest_spec_for(name) end
返回最新的规范,如果 prerelease
为 true,则可以选择包括预发布规范。
# File rubygems/specification.rb, line 1054 def self.latest_specs(prerelease = false) specification_record.latest_specs(prerelease) end
从 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
加载默认规范。它应该只调用一次。
# 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
Specification
构造函数。将默认值分配给属性,并为了进一步初始化而 yield 自身。可以选择性地采用 name
和 version
。
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
Specification
必须非空的属性
# File rubygems/specification.rb, line 1121 def self.non_nil_attributes @@non_nil_attributes.dup end
确保 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
返回所有过时的本地 gem 名称的列表。此方法很重,因为它必须从服务器获取规范。
如果要检索最新的远程版本,请使用 outdated_and_latest_version
。
# File rubygems/specification.rb, line 1146 def self.outdated outdated_and_latest_version.map {|local, _| local.name } end
枚举过时的本地 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
从已知规范中删除 spec
。
# File rubygems/specification.rb, line 865 def self.remove_spec(spec) specification_record.remove_spec(spec) end
name
是必需属性吗?
# File rubygems/specification.rb, line 1182 def self.required_attribute?(name) @@required_attributes.include? name.to_sym end
必需的规范属性
# File rubygems/specification.rb, line 1189 def self.required_attributes @@required_attributes.dup end
重置已知规范的列表,运行在 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
跟踪所有当前已知的规范
# File rubygems/specification.rb, line 1233 def self.specification_record @specification_record ||= Gem::SpecificationRecord.new(dirs) end
为每个已安装的 gem 返回一个 Gem::StubSpecification
# File rubygems/specification.rb, line 798 def self.stubs specification_record.stubs end
为名为 name
的已安装 gem 返回一个 Gem::StubSpecification
,仅返回与 Gem.platforms
匹配的存根
# File rubygems/specification.rb, line 817 def self.stubs_for(name) specification_record.stubs_for(name) end
文档:此方法需要文档化或标记为 nodoc
# File rubygems/specification.rb, line 1238 def self.unresolved_deps @unresolved_deps ||= Hash.new {|h, n| h[n] = Gem::Dependency.new n } end
私有类方法
# File rubygems/specification.rb, line 1016 def self.unresolved_specs unresolved_deps.values.flat_map(&:to_specs) end
公共实例方法
仅转储关键实例变量。
# 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
缩写规范以进行下载。缩写规范仅用于搜索、下载和相关活动,不需要特定于部署的信息(例如,文件列表)。因此,我们缩写规范,使其更小以便更快地下载。
# File rubygems/specification.rb, line 1441 def abbreviate self.files = [] self.test_files = [] self.rdoc_options = [] self.extra_rdoc_files = [] self.cert_chain = [] end
激活此规范,将其注册为已加载的规范并将其 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
激活此规范所有明确解析的运行时依赖项。将任何不明确的依赖项添加到未解析的列表中,以便稍后根据需要进行解析。
# 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
返回一个数组,其中 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
将此规范的 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
# 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
返回已安装 gem 的 bin 目录的完整路径。
注意:不要将其与 bindir
混淆,bindir
只是 “bin”,而不是完整路径。
# File rubygems/specification.rb, line 1546 def bin_dir @bin_dir ||= File.join gem_dir, bindir end
返回此 gem 中名为 name
的可执行文件的完整路径。
# File rubygems/specification.rb, line 1553 def bin_file(name) File.join bin_dir, name end
返回用于安装 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 目录的完整路径
# File rubygems/specification.rb, line 1608 def build_info_dir File.join base_dir, "build_info" end
返回包含安装 gem 时生成的构建信息的文件完整路径
# File rubygems/specification.rb, line 1616 def build_info_file File.join build_info_dir, "#{full_name}.info" end
返回包含此规范缓存 gem 的缓存目录的完整路径。
# File rubygems/specification.rb, line 1624 def cache_dir @cache_dir ||= File.join base_dir, "cache" end
返回此规范缓存 gem 的完整路径。
# File rubygems/specification.rb, line 1631 def cache_file @cache_file ||= File.join cache_dir, "#{full_name}.gem" end
返回当前已加载规范的任何可能冲突。
# 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
此 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
此 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
规范属性 name
的默认值
# File rubygems/specification.rb, line 1742 def default_value(name) @@default_value[name] end
此 gem 依赖的 Gem::Dependency
对象列表。
使用 add_dependency
或 add_development_dependency
向 gem 添加依赖项。
# File rubygems/specification.rb, line 1752 def dependencies @dependencies ||= [] end
返回所有依赖此 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
返回与此规范的运行时依赖项匹配的所有规范。
# File rubygems/specification.rb, line 1781 def dependent_specs runtime_dependencies.flat_map(&:to_specs) end
此 gem 的详细描述。另请参见 summary
# File rubygems/specification.rb, line 1788 def description=(str) @description = str.to_s end
用于开发的依赖项列表
# File rubygems/specification.rb, line 1795 def development_dependencies dependencies.select {|d| d.type == :development } end
返回此规范文档目录的完整路径。如果给出了 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
executables
的单数访问器
# File rubygems/specification.rb, line 1837 def executable (val = executables) && val.first end
executables
的单数访问器
# File rubygems/specification.rb, line 1844 def executable=(o) self.executables = [o] end
将 executables 设置为 value
,确保它是一个数组。
# File rubygems/specification.rb, line 1851 def executables=(value) @executables = Array(value) end
将 extensions 设置为 extensions
,确保它是一个数组。
# File rubygems/specification.rb, line 1858 def extensions=(extensions) @extensions = Array extensions end
将 extra_rdoc_files
设置为 files
,确保它是一个数组。
# File rubygems/specification.rb, line 1865 def extra_rdoc_files=(files) @extra_rdoc_files = Array files end
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
,确保它是一个数组。
# File rubygems/specification.rb, line 1881 def files=(files) @files = Array files end
创建一个没有在运行时使用的大型 blob 的重复规范。
# File rubygems/specification.rb, line 1899 def for_cache spec = dup spec.files = nil spec.test_files = nil spec end
# File rubygems/specification.rb, line 1908 def full_name @full_name ||= super end
# File rubygems/specification.rb, line 1920 def gems_dir @gems_dir ||= File.join(base_dir, "gems") end
如果当前已加载规范存在可能的冲突,则返回 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
复制 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
# 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
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
licenses
的单数访问器
# File rubygems/specification.rb, line 2082 def license licenses.first end
用于设置许可证的复数访问器
有关详细信息,请参见 license=
# File rubygems/specification.rb, line 2091 def licenses @licenses ||= [] end
此规范是否缺少其扩展?当此项返回 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
返回一个表示此 Specification
的 NameTuple
# File rubygems/specification.rb, line 2159 def name_tuple Gem::NameTuple.new name, version, original_platform end
规范化文件列表,以便
-
所有文件列表都删除重复项。
-
在
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
此 gem 运行的平台。有关详细信息,请参见 Gem::Platform
。
# File rubygems/specification.rb, line 2185 def platform @new_platform ||= Gem::Platform::RUBY # rubocop:disable Naming/MemoizedInstanceVariableName end
将 rdoc_options
设置为 value
,并确保它是一个数组。
# File rubygems/specification.rb, line 2251 def rdoc_options=(options) @rdoc_options = Array options end
对 require_paths
的单数访问器
# File rubygems/specification.rb, line 2258 def require_path (val = require_paths) && val.first end
对 require_paths
的单数访问器
# File rubygems/specification.rb, line 2265 def require_path=(path) self.require_paths = Array(path) end
将 requirements 设置为 req
,并确保它是一个数组。
# File rubygems/specification.rb, line 2272 def requirements=(req) @requirements = Array req end
将 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 目录的完整路径。
# File rubygems/specification.rb, line 2283 def ri_dir @ri_dir ||= File.join base_dir, "ri", full_name end
运行时将自动激活的依赖项列表。
# File rubygems/specification.rb, line 2316 def runtime_dependencies dependencies.select(&:runtime?) end
清理规范中的描述性字段。有时,非 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
清理单个字符串。
# 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
检查此规范是否满足 dependency
的要求。
# File rubygems/specification.rb, line 2332 def satisfies_requirement?(dependency) @name == dependency.name && dependency.requirement.satisfied_by?(@version) end
返回一个可以用来在 sort_by 中对规范进行排序的对象。
# File rubygems/specification.rb, line 2340 def sort_obj [@name, @version, Gem::Platform.sort_priority(@new_platform)] end
返回包含此规范的 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
返回此规范的 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
gemspec 的默认名称。另请参见 file_name
spec.spec_name # => "example-1.0.gemspec"
# File rubygems/specification.rb, line 2372 def spec_name "#{full_name}.gemspec" end
# File rubygems/specification.rb, line 2616 def stubbed? false end
此 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
返回此规范的 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
返回此规范的 Ruby 轻量级代码表示形式,仅用于索引。
请参阅 to_ruby
。
# File rubygems/specification.rb, line 2498 def to_ruby_for_cache for_cache.to_ruby end
返回 self
# File rubygems/specification.rb, line 2509 def to_spec self end
递归遍历此规范的依赖项,为每次跳跃执行 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
检查规范是否包含所有必需的字段,并进行非常基本的健全性检查。
如果规范未通过检查,则引发 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
# File rubygems/specification.rb, line 2596 def validate_dependencies Gem::SpecificationPolicy.new(self).validate_dependencies end
# File rubygems/specification.rb, line 2587 def validate_for_resolution Gem::SpecificationPolicy.new(self).validate_for_resolution end
# File rubygems/specification.rb, line 2591 def validate_metadata Gem::SpecificationPolicy.new(self).validate_metadata end
# File rubygems/specification.rb, line 2601 def validate_permissions Gem::SpecificationPolicy.new(self).validate_permissions end
将版本设置为 version
。
# File rubygems/specification.rb, line 2609 def version=(version) @version = Gem::Version.create(version) return if @version.nil? invalidate_memoized_attributes end
私有实例方法
添加对 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
查找满足 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
使可错误生成、替换或错过文件(由于用于计算它们的某些属性的更改)的记忆实例变量过期。
# File rubygems/specification.rb, line 2053 def invalidate_memoized_attributes @full_name = nil @cache_file = nil end
返回包含给定对象的 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
如果此 gem 与 other
具有相同的属性,则为 True。
# File rubygems/specification.rb, line 2323 def same_attributes?(spec) @@attributes.all? {|name, _default| send(name) == spec.send(name) } end