模块 Gem

RubyGems 是 Ruby 用于发布和管理第三方库的标准。

有关用户文档,请参阅

有关 gem 开发人员文档,请参阅

有关 RubyGems 的更多文档,请访问

RubyGems 插件

RubyGems 将在每个已安装 gem 或 $LOAD_PATH 的最新版本中加载插件。插件必须命名为“rubygems_plugin”(.rb、.so 等)并放置在 gem 的 require_path 根目录下。插件安装在特殊位置并在启动时加载。

有关插件示例,请参阅 Graph gem,它添加了 gem graph 命令。

RubyGems 默认值,打包

RubyGems 默认值存储在 lib/rubygems/defaults.rb 中。如果您正在打包 RubyGems 或实现 Ruby,您可以更改 RubyGems 的默认值。

对于 RubyGems 打包程序,请提供 lib/rubygems/defaults/operating_system.rb 并覆盖 lib/rubygems/defaults.rb 中的任何默认值。

对于 Ruby 实现者,请提供 lib/rubygems/defaults/#{RUBY_ENGINE}.rb 并覆盖 lib/rubygems/defaults.rb 中的任何默认值。

如果您需要 RubyGems 在安装或卸载时执行额外的工作,您的默认值覆盖文件可以设置安装前/后和卸载前/后挂钩。请参阅 Gem::pre_installGem::pre_uninstallGem::post_installGem::post_uninstall

错误

您可以在 GitHub 上向 RubyGems 错误跟踪器 提交错误。

致谢

RubyGems 目前由 Eric Hodel 维护。

RubyGems 最初由 RubyConf 2003 开发,开发人员包括:

贡献者

(如果您的姓名缺失,请告知我们!)

许可证

有关权限,请参阅 LICENSE.txt。

谢谢!

-RubyGems 团队

常量

DEFAULT_HOST
GEM_DEP_FILES
LOADED_SPECS_MUTEX
MARSHAL_SPEC_DIR

远程存储库上 Marshal 快速 gemspecs 的位置

RDoc

Gem::RDoc 提供方法,用于在 gem 安装后为已安装的 gem 生成 RDoc 和 ri 数据。

此文件由 RubyGems 1.9 及更高版本自动加载。

REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES

gem 存储库中默认 gem 的子目录

REPOSITORY_SUBDIRECTORIES

gem 存储库中的子目录

RUBYGEMS_DIR
VERSION
WIN_PATTERNS

匹配 Windows Ruby 平台的正则表达式 Array

属性

disable_system_update_message[RW]

RubyGems 发行版(如操作系统包管理器)可以通过将此设置为错误消息来禁用 RubyGems 更新,该错误消息在 gem update –system 时打印给最终用户,而不是实际更新。

discover_gems_on_require[RW]

RubyGems 是否应该增强内置的 ‘require` 以自动检查所需路径是否出现在已安装的 gem 中,并自动激活它们并将它们添加到 `$LOAD_PATH`。

done_installing_hooks[R]

Gem::DependencyInstaller 安装一组 gem 后要运行的钩子列表

gemdeps[R]

GemDependencyAPI 对象,在调用 .use_gemdeps 时设置。它包含 Gemfile 中的所有信息。

loaded_specs[R]

已加载的 Gem::SpecificationHash,按名称键控

post_build_hooks[R]

Gem::Installer#install 提取文件并构建扩展后运行的钩子列表。

post_install_hooks[R]

Gem::Installer#install 完成安装后运行的钩子列表。

post_reset_hooks[R]

在运行 Gem::Specification.reset 后运行的钩子列表。

post_uninstall_hooks[R]

Gem::Uninstaller#uninstall 完成安装后运行的钩子列表。

pre_install_hooks[R]

Gem::Installer#install 执行任何操作之前运行的钩子列表。

pre_reset_hooks[R]

在运行 Gem::Specification.reset 之前运行的钩子列表。

pre_uninstall_hooks[R]

Gem::Uninstaller#uninstall 执行任何操作之前运行的钩子列表。

公共类方法

activated_gem_paths() 点击切换源代码

来自已激活 gem 的 +$LOAD_PATH+ 中的路径数量。用于在 require 期间优先考虑 -IENV['RUBYLIB'] 条目。

# File lib/rubygems.rb, line 572
def self.activated_gem_paths
  @activated_gem_paths ||= 0
end
add_to_load_path(*paths) 点击切换源代码

将路径列表添加到 $LOAD_PATH 的适当位置。

# File lib/rubygems.rb, line 579
def self.add_to_load_path(*paths)
  @activated_gem_paths = activated_gem_paths + paths.size

  # gem directories must come after -I and ENV['RUBYLIB']
  $LOAD_PATH.insert(Gem.load_path_insert_index, *paths)
end
bin_path(name, exec_name = nil, *requirements) 点击切换源代码

Find gem name 的可执行文件的完整路径。如果未给出 exec_name,则会引发异常,否则将返回指定可执行文件的路径。requirements 允许您指定特定 gem 版本。

# File lib/rubygems.rb, line 235
def self.bin_path(name, exec_name = nil, *requirements)
  requirements = Gem::Requirement.default if
    requirements.empty?

  find_spec_for_exe(name, exec_name, requirements).bin_file exec_name
end
binary_mode() 点击切换源代码

以纯二进制方式读取文件所需的模式。

# File lib/rubygems.rb, line 289
def self.binary_mode
  "rb"
end
bindir(install_dir=Gem.dir) 点击切换源代码

安装 gem 可执行文件的路径。

# File lib/rubygems.rb, line 296
def self.bindir(install_dir=Gem.dir)
  return File.join install_dir, "bin" unless
    install_dir.to_s == Gem.default_dir.to_s
  Gem.default_bindir
end
cache_home() 点击切换源代码

用户缓存目录的标准位置路径。

# File lib/rubygems/defaults.rb, line 147
def self.cache_home
  @cache_home ||= ENV["XDG_CACHE_HOME"] || File.join(Gem.user_home, ".cache")
end
clear_default_specs() 点击切换源代码

清除默认的 gem 相关变量。用于测试。

# File lib/rubygems.rb, line 1234
def clear_default_specs
  @path_to_default_spec_map.clear
end
clear_paths() 点击切换源代码

重置 dirpath 值。下次请求 dirpath 时,将从头开始计算值。这主要用于单元测试,以提供测试隔离。

# File lib/rubygems.rb, line 314
def self.clear_paths
  @paths         = nil
  @user_home     = nil
  Gem::Specification.reset
  Gem::Security.reset if defined?(Gem::Security)
end
config_file() 点击切换源代码

用户 .gemrc 文件的标准位置路径。

# File lib/rubygems/defaults.rb, line 133
def self.config_file
  @config_file ||= find_config_file
end
config_home() 点击切换源代码

用户配置目录的标准位置路径。

# File lib/rubygems/defaults.rb, line 114
def self.config_home
  @config_home ||= ENV["XDG_CONFIG_HOME"] || File.join(Gem.user_home, ".config")
end
configuration() 点击切换源代码

gem 的标准配置对象。

# File lib/rubygems.rb, line 324
def self.configuration
  @configuration ||= Gem::ConfigFile.new []
end
configuration=(config) 点击切换源代码

使用给定的配置对象(实现 ConfigFile 协议)作为标准配置对象。

# File lib/rubygems.rb, line 332
def self.configuration=(config)
  @configuration = config
end
data_home() 点击切换源代码

用户数据目录的标准位置路径。

# File lib/rubygems/defaults.rb, line 154
def self.data_home
  @data_home ||= ENV["XDG_DATA_HOME"] || File.join(Gem.user_home, ".local", "share")
end
default_bindir() 点击切换源代码

二进制文件的默认目录。

# File lib/rubygems/defaults.rb, line 204
def self.default_bindir
  RbConfig::CONFIG["bindir"]
end
default_cert_path() 点击切换源代码

默认的签名证书链路径。

# File lib/rubygems/defaults.rb, line 228
def self.default_cert_path
  default_cert_path = File.join Gem.user_home, ".gem", "gem-public_cert.pem"

  unless File.exist?(default_cert_path)
    default_cert_path = File.join Gem.data_home, "gem", "gem-public_cert.pem"
  end

  default_cert_path
end
default_dir() 点击切换源代码

如果环境中未指定备用值,则使用的默认主目录路径。

# File lib/rubygems/defaults.rb, line 37
def self.default_dir
  @default_dir ||= File.join(RbConfig::CONFIG["rubylibprefix"], "gems", RbConfig::CONFIG["ruby_version"])
end
default_exec_format() 点击切换源代码

从 Ruby 的安装名称推断 Ruby 的 –program-prefix 和 –program-suffix。

# File lib/rubygems/defaults.rb, line 186
def self.default_exec_format
  exec_format = begin
                  RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s")
                rescue StandardError
                  "%s"
                end

  unless exec_format.include?("%s")
    raise Gem::Exception,
      "[BUG] invalid exec_format #{exec_format.inspect}, no %s"
  end

  exec_format
end
default_ext_dir_for(base_dir) 点击切换源代码

返回指定 RubyGems 基目录的二进制扩展目录,如果无法确定该目录,则返回 nil。

默认情况下,二进制扩展位于与其 Ruby 对应文件并排,因此返回 nil。

# File lib/rubygems/defaults.rb, line 48
def self.default_ext_dir_for(base_dir)
  nil
end
default_key_path() 点击切换源代码

默认的签名密钥路径。

# File lib/rubygems/defaults.rb, line 215
def self.default_key_path
  default_key_path = File.join Gem.user_home, ".gem", "gem-private_key.pem"

  unless File.exist?(default_key_path)
    default_key_path = File.join Gem.data_home, "gem", "gem-private_key.pem"
  end

  default_key_path
end
default_path() 点击切换源代码

默认的 gem 加载路径。

# File lib/rubygems/defaults.rb, line 175
def self.default_path
  path = []
  path << user_dir if user_home && File.exist?(user_home)
  path << default_dir
  path << vendor_dir if vendor_dir && File.directory?(vendor_dir)
  path
end
default_rubygems_dirs() 点击切换源代码

RubyGems 的 .rb 文件和 bin 文件安装的路径

# File lib/rubygems/defaults.rb, line 55
def self.default_rubygems_dirs
  nil # default to standard layout
end
default_sources() 点击切换源代码

一个包含 RubyGems 默认源的 Array

# File lib/rubygems/defaults.rb, line 15
def self.default_sources
  %w[https://rubygems.org.cn/]
end
default_spec_cache_dir() 点击切换源代码

如果环境中未指定备用值,则要使用的默认规范目录路径

# File lib/rubygems/defaults.rb, line 23
def self.default_spec_cache_dir
  default_spec_cache_dir = File.join Gem.user_home, ".gem", "specs"

  unless File.exist?(default_spec_cache_dir)
    default_spec_cache_dir = File.join Gem.cache_home, "gem", "specs"
  end

  default_spec_cache_dir
end
default_specifications_dir() 点击切换源代码

默认 gem 的规范文件路径。

# File lib/rubygems/defaults.rb, line 62
def self.default_specifications_dir
  @default_specifications_dir ||= File.join(Gem.default_dir, "specifications", "default")
end
deflate(data) 点击切换源代码

一个 Zlib::Deflate.deflate 包装器

# File lib/rubygems.rb, line 339
def self.deflate(data)
  require "zlib"
  Zlib::Deflate.deflate data
end
dir() 点击切换源代码

gem 安装的路径。

# File lib/rubygems.rb, line 387
def self.dir
  paths.home
end
done_installing(&hook) 点击切换源代码

添加一个安装后钩子,当 Gem::DependencyInstaller#install 完成时,该钩子将传递一个 Gem::DependencyInstaller 和一个已安装规范列表

# File lib/rubygems.rb, line 683
def self.done_installing(&hook)
  @done_installing_hooks << hook
end
dynamic_library_suffixes() 点击切换源代码

动态库可要求路径的后缀。

# File lib/rubygems.rb, line 948
def self.dynamic_library_suffixes
  @dynamic_library_suffixes ||= suffixes - [".rb"]
end
ensure_default_gem_subdirectories(dir = Gem.dir, mode = nil) 点击切换源代码

静默确保 Gem 目录 dir 包含处理默认 gem 的所有正确子目录。如果由于权限问题无法创建目录,我们将静默继续。

如果给定 mode,则以该模式创建缺失的目录。

永远不会创建世界可写目录。

# File lib/rubygems.rb, line 421
def self.ensure_default_gem_subdirectories(dir = Gem.dir, mode = nil)
  ensure_subdirectories(dir, mode, REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES)
end
ensure_gem_subdirectories(dir = Gem.dir, mode = nil) 点击切换源代码

静默确保 Gem 目录 dir 包含所有正确的子目录。如果由于权限问题无法创建目录,我们将静默继续。

如果给定 mode,则以该模式创建缺失的目录。

永远不会创建世界可写目录。

# File lib/rubygems.rb, line 408
def self.ensure_gem_subdirectories(dir = Gem.dir, mode = nil)
  ensure_subdirectories(dir, mode, REPOSITORY_SUBDIRECTORIES)
end
env_requirement(gem_name) 点击切换源代码
# File lib/rubygems.rb, line 816
def self.env_requirement(gem_name)
  @env_requirements_by_name ||= {}
  @env_requirements_by_name[gem_name] ||= begin
    req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0"
    Gem::Requirement.create(req)
  end
end
find_config_file() 点击切换源代码

查找用户的配置文件

# File lib/rubygems/defaults.rb, line 121
def self.find_config_file
  gemrc = File.join Gem.user_home, ".gemrc"
  if File.exist? gemrc
    gemrc
  else
    File.join Gem.config_home, "gem", "gemrc"
  end
end
find_default_spec(path) 点击切换源代码

pathFind 默认 gem 的 Gem::Specification

# File lib/rubygems.rb, line 1219
def find_default_spec(path)
  @path_to_default_spec_map[path]
end
find_files(glob, check_load_path=true) 点击切换源代码

返回与 glob 匹配的路径列表,gem 可以使用这些路径从其他 gem 中获取功能。例如

Gem.find_files('rdoc/discover').each do |path| load path end

如果 check_load_path 为真(默认值),则 find_files 还会搜索 $LOAD_PATH 中的文件以及 gem。

请注意,find_files 将返回所有文件,即使它们来自同一 gem 的不同版本。另请参阅 find_latest_files

# File lib/rubygems.rb, line 472
def self.find_files(glob, check_load_path=true)
  files = []

  files = find_files_from_load_path glob if check_load_path

  gem_specifications = @gemdeps ? Gem.loaded_specs.values : Gem::Specification.stubs

  files.concat gem_specifications.map {|spec|
    spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
  }.flatten

  # $LOAD_PATH might contain duplicate entries or reference
  # the spec dirs directly, so we prune.
  files.uniq! if check_load_path

  files
end
find_latest_files(glob, check_load_path=true) 点击切换源代码

返回与 glob 匹配的路径列表,这些路径来自最新 gem,gem 可以使用这些路径从其他 gem 中获取功能。例如

Gem.find_latest_files('rdoc/discover').each do |path| load path end

如果 check_load_path 为真(默认值),则 find_latest_files 还会搜索 $LOAD_PATH 中的文件以及 gem。

find_files 不同,find_latest_files 只会返回来自 gem 最新版本的那些文件。

# File lib/rubygems.rb, line 509
def self.find_latest_files(glob, check_load_path=true)
  files = []

  files = find_files_from_load_path glob if check_load_path

  files.concat Gem::Specification.latest_specs(true).map {|spec|
    spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
  }.flatten

  # $LOAD_PATH might contain duplicate entries or reference
  # the spec dirs directly, so we prune.
  files.uniq! if check_load_path

  files
end
find_unresolved_default_spec(path) 点击切换源代码

pathFind 未解析的默认 gem 的 Gem::Specification

# File lib/rubygems.rb, line 1226
def find_unresolved_default_spec(path)
  default_spec = @path_to_default_spec_map[path]
  default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
end
finish_resolve(request_set=Gem::RequestSet.new) 点击切换源代码
# File lib/rubygems.rb, line 220
def self.finish_resolve(request_set=Gem::RequestSet.new)
  request_set.import Gem::Specification.unresolved_deps.values
  request_set.import Gem.loaded_specs.values.map {|s| Gem::Dependency.new(s.name, s.version) }

  request_set.resolve_current.each do |s|
    s.full_spec.activate
  end
end
host() 点击切换源代码

获取默认的 RubyGems API 主机。这通常是 https://rubygems.org.cn

# File lib/rubygems.rb, line 544
def self.host
  @host ||= Gem::DEFAULT_HOST
end
host=(host) 点击切换源代码

Set 默认的 RubyGems API 主机。

# File lib/rubygems.rb, line 550
def self.host=(host)
  @host = host
end
install(name, version = Gem::Requirement.default, *options) 点击切换源代码

顶级安装帮助方法。允许您以交互方式安装 gem

% irb
>> Gem.install "minitest"
Fetching: minitest-5.14.0.gem (100%)
=> [#<Gem::Specification:0x1013b4528 @name="minitest", ...>]
# File lib/rubygems.rb, line 533
def self.install(name, version = Gem::Requirement.default, *options)
  require_relative "rubygems/dependency_installer"
  inst = Gem::DependencyInstaller.new(*options)
  inst.install name, version
  inst.installed_gems
end
java_platform?() 点击切换源代码

这是一个 Java 平台吗?

# File lib/rubygems.rb, line 1004
def self.java_platform?
  RUBY_PLATFORM == "java"
end
latest_rubygems_version() 点击切换源代码

返回 RubyGems 的最新发布版本。

# File lib/rubygems.rb, line 841
def self.latest_rubygems_version
  latest_version_for("rubygems-update") ||
    raise("Can't find 'rubygems-update' in any repo. Check `gem source list`.")
end
latest_spec_for(name) 点击切换源代码

返回 gem name 的最新发布版本规范。

# File lib/rubygems.rb, line 828
def self.latest_spec_for(name)
  dependency   = Gem::Dependency.new name
  fetcher      = Gem::SpecFetcher.fetcher
  spec_tuples, = fetcher.spec_for_dependency dependency

  spec, = spec_tuples.last

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

返回 gem name 的最新发布版本的版本。

# File lib/rubygems.rb, line 849
def self.latest_version_for(name)
  latest_spec_for(name)&.version
end
load_env_plugins() 点击切换源代码

在 $LOAD_PATH 中查找所有 ‘rubygems_plugin’ 文件并加载它们。

# File lib/rubygems.rb, line 1046
def self.load_env_plugins
  load_plugin_files find_files_from_load_path("rubygems_plugin")
end
load_path_insert_index() 点击切换源代码

将激活的 gem 路径插入 $LOAD_PATH 的索引。默认情况下,激活的 gem 的路径将插入到 site lib 目录之前。

# File lib/rubygems.rb, line 558
def self.load_path_insert_index
  $LOAD_PATH.each_with_index do |path, i|
    return i if path.instance_variable_defined?(:@gem_prelude_index)
  end

  index = $LOAD_PATH.index RbConfig::CONFIG["sitelibdir"]

  index || 0
end
load_plugins() 点击切换源代码

在标准位置查找 rubygems 插件文件并加载它们。

# File lib/rubygems.rb, line 1037
def self.load_plugins
  Gem.path.each do |gem_path|
    load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir(gem_path))
  end
end
load_safe_marshal() 点击切换源代码
# File lib/rubygems.rb, line 604
def self.load_safe_marshal
  return if @safe_marshal_loaded

  require_relative "rubygems/safe_marshal"

  @safe_marshal_loaded = true
end
load_yaml() 点击切换源代码

加载 YAML,优先使用 Psych

# File lib/rubygems.rb, line 591
def self.load_yaml
  return if @yaml_loaded

  require "psych"
  require_relative "rubygems/psych_tree"

  require_relative "rubygems/safe_yaml"

  @yaml_loaded = true
end
location_of_caller(depth = 1) 点击切换源代码

此方法的调用者的调用者的文件名和行号。

depth 表示它应该向上遍历调用堆栈的层数。

例如:

def a; Gem.location_of_caller; end a #=> [“x.rb”, 2] # (它将根据文件名和行号而有所不同)

def b; c; end def c; Gem.location_of_caller(2); end b #=> [“x.rb”, 6] # (它将根据文件名和行号而有所不同)

# File lib/rubygems.rb, line 626
def self.location_of_caller(depth = 1)
  caller[depth] =~ /(.*?):(\d+).*?$/i
  file = $1
  lineno = $2.to_i

  [file, lineno]
end
marshal_version() 点击切换源代码

您 Ruby 版本的 Marshal 格式。

# File lib/rubygems.rb, line 637
def self.marshal_version
  "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
end
needs() { |rs| ... } 点击切换源代码
# File lib/rubygems.rb, line 212
def self.needs
  rs = Gem::RequestSet.new

  yield rs

  finish_resolve rs
end
open_file(path, flags) { |io| ... } 点击切换源代码

使用给定的标志打开文件,并在 Windows 上使用 flock 保护访问权限。

# File lib/rubygems.rb, line 776
def self.open_file(path, flags, &block)
  File.open(path, flags) do |io|
    if !java_platform? && win_platform?
      begin
        io.flock(File::LOCK_EX)
      rescue Errno::ENOSYS, Errno::ENOTSUP
      end
    end
    yield io
  end
rescue Errno::ENOLCK # NFS
  if Thread.main != Thread.current
    raise
  else
    File.open(path, flags) do |io|
      yield io
    end
  end
end
operating_system_defaults() 点击切换源代码

Ruby 打包程序的 gem 命令的默认选项。

这里的选项应结构化为一个字符串数组,其中字符串“gem”命令名称作为键,字符串的默认选项作为值。

示例

def self.operating_system_defaults

{
    'install' => '--no-rdoc --no-ri --env-shebang',
    'update' => '--no-rdoc --no-ri --env-shebang'
}

end

# File lib/rubygems/defaults.rb, line 286
def self.operating_system_defaults
  {}
end
path() 点击切换源代码
# File lib/rubygems.rb, line 391
def self.path
  paths.path
end
path_separator() 点击切换源代码

如何分割 String Gem 路径。对于奇特的平台可以覆盖。

# File lib/rubygems/defaults.rb, line 168
def self.path_separator
  File::PATH_SEPARATOR
end
paths() 点击切换源代码

检索 RubyGems 用于查找文件的 PathSupport 对象。

# File lib/rubygems.rb, line 347
def self.paths
  @paths ||= Gem::PathSupport.new(ENV)
end
paths=(env) 点击切换源代码

env 初始化要使用的文件系统路径。env 是一个类似哈希的对象(通常是 ENV),它被查询以获取“GEM_HOME”、“GEM_PATH”和“GEM_SPEC_CACHE”键。env 哈希的键应该是字符串,哈希的值应该是字符串或 nil

# File lib/rubygems.rb, line 357
  def self.paths=(env)
    clear_paths
    target = {}
    env.each_pair do |k,v|
      case k
      when "GEM_HOME", "GEM_PATH", "GEM_SPEC_CACHE"
        case v
        when nil, String
          target[k] = v
        when Array
          unless Gem::Deprecate.skip
            warn <<-EOWARN
Array values in the parameter to `Gem.paths=` are deprecated.
Please use a String or nil.
An Array (#{env.inspect}) was passed in from #{caller[3]}
            EOWARN
          end
          target[k] = v.join File::PATH_SEPARATOR
        end
      else
        target[k] = v
      end
    end
    @paths = Gem::PathSupport.new ENV.to_hash.merge(target)
    Gem::Specification.dirs = @paths.path
  end
platform_defaults() 点击切换源代码

Ruby 实现者的 gem 命令的默认选项。

这里的选项应结构化为一个字符串数组,其中字符串“gem”命令名称作为键,字符串的默认选项作为值。

示例

def self.platform_defaults

{
    'install' => '--no-rdoc --no-ri --env-shebang',
    'update' => '--no-rdoc --no-ri --env-shebang'
}

end

# File lib/rubygems/defaults.rb, line 305
def self.platform_defaults
  {}
end
platforms() 点击切换源代码

此 RubyGems 支持的平台的 Array

# File lib/rubygems.rb, line 651
def self.platforms
  @platforms ||= []
  if @platforms.empty?
    @platforms = [Gem::Platform::RUBY, Gem::Platform.local]
  end
  @platforms
end
platforms=(platforms) 点击切换源代码

此 RubyGems 支持的平台的 Set 数组(主要用于测试)。

# File lib/rubygems.rb, line 644
def self.platforms=(platforms)
  @platforms = platforms
end
plugin_suffix_pattern() 点击切换源代码

可要求插件后缀的 glob 模式。

# File lib/rubygems.rb, line 921
def self.plugin_suffix_pattern
  @plugin_suffix_pattern ||= "_plugin#{suffix_pattern}"
end
plugin_suffix_regexp() 点击切换源代码

可要求插件后缀的 Regexp

# File lib/rubygems.rb, line 928
def self.plugin_suffix_regexp
  @plugin_suffix_regexp ||= /_plugin#{suffix_regexp}\z/
end
plugindir(install_dir=Gem.dir) 点击切换源代码

rubygems 插件要安装的路径。

# File lib/rubygems.rb, line 305
def self.plugindir(install_dir=Gem.dir)
  File.join install_dir, "plugins"
end
post_build(&hook) 点击切换源代码

添加一个构建后钩子,当调用 Gem::InstallerGem::Installer#install 方法时,该钩子将传递一个 Gem::Installer 实例。该钩子在 gem 解压和扩展构建完成,但可执行文件或 gemspec 尚未写入之前调用。如果钩子返回 false,则 gem 的文件将被删除,安装将被中止。

# File lib/rubygems.rb, line 666
def self.post_build(&hook)
  @post_build_hooks << hook
end
post_install(&hook) 点击切换源代码

添加一个安装后钩子,当调用 Gem::InstallerGem::Installer#install 方法时,该钩子将传递一个 Gem::Installer 实例。

# File lib/rubygems.rb, line 674
def self.post_install(&hook)
  @post_install_hooks << hook
end
post_reset(&hook) 点击切换源代码

添加一个钩子,该钩子将在运行 Gem::Specification.reset 之后运行。

# File lib/rubygems.rb, line 691
def self.post_reset(&hook)
  @post_reset_hooks << hook
end
post_uninstall(&hook) 点击切换源代码

添加一个卸载后钩子,当调用 Gem::UninstallerGem::Uninstaller#uninstall 方法时,该钩子将传递一个 Gem::Uninstaller 实例和被卸载的 spec。

# File lib/rubygems.rb, line 700
def self.post_uninstall(&hook)
  @post_uninstall_hooks << hook
end
pre_install(&hook) 点击切换源代码

添加一个安装前钩子,当调用 Gem::InstallerGem::Installer#install 方法时,该钩子将传递一个 Gem::Installer 实例。如果钩子返回 false,则安装将被中止。

# File lib/rubygems.rb, line 709
def self.pre_install(&hook)
  @pre_install_hooks << hook
end
pre_reset(&hook) 点击切换源代码

添加一个钩子,该钩子将在运行 Gem::Specification.reset 之前运行。

# File lib/rubygems.rb, line 717
def self.pre_reset(&hook)
  @pre_reset_hooks << hook
end
pre_uninstall(&hook) 点击切换源代码

添加一个卸载前钩子,当调用 Gem::UninstallerGem::Uninstaller#uninstall 方法时,该钩子将传递一个 Gem::Uninstaller 实例和将要被卸载的 spec。

# File lib/rubygems.rb, line 726
def self.pre_uninstall(&hook)
  @pre_uninstall_hooks << hook
end
prefix() 点击切换源代码

此 RubyGems 安装所在的目录前缀。如果您的前缀位于标准位置(即,rubygems 安装在您期望的位置),则 prefix 返回 nil。

# File lib/rubygems.rb, line 735
def self.prefix
  prefix = File.dirname RUBYGEMS_DIR

  if prefix != File.expand_path(RbConfig::CONFIG["sitelibdir"]) &&
     prefix != File.expand_path(RbConfig::CONFIG["libdir"]) &&
     File.basename(RUBYGEMS_DIR) == "lib"
    prefix
  end
end
read_binary(path) 点击切换源代码

在所有平台上以二进制模式安全地读取文件。

# File lib/rubygems.rb, line 755
def self.read_binary(path)
  open_file(path, "rb+", &:read)
rescue Errno::EACCES, Errno::EROFS
  open_file(path, "rb", &:read)
end
refresh() 点击切换源代码

从磁盘刷新可用的 gems。

# File lib/rubygems.rb, line 748
def self.refresh
  Gem::Specification.reset
end
register_default_spec(spec) 点击切换源代码

为默认 gem 注册一个 Gem::Specification

支持两种格式的规范:

  • MRI 2.0 风格,其中 spec.files 包含未加前缀的 require 名称。spec 的文件名将按原样注册。

  • 新风格,其中 spec.files 包含以 spec.require_paths 中的路径为前缀的文件。在注册 spec 的文件名之前,会剥离前缀。未加前缀的文件将被忽略。

# File lib/rubygems.rb, line 1194
def register_default_spec(spec)
  extended_require_paths = spec.require_paths.map {|f| f + "/" }
  new_format = extended_require_paths.any? {|path| spec.files.any? {|f| f.start_with? path } }

  if new_format
    prefix_group = extended_require_paths.join("|")
    prefix_pattern = /^(#{prefix_group})/
  end

  spec.files.each do |file|
    if new_format
      file = file.sub(prefix_pattern, "")
      next unless $~
    end

    spec.activate if already_loaded?(file)

    @path_to_default_spec_map[file] = spec
    @path_to_default_spec_map[file.sub(suffix_regexp, "")] = spec
  end
end
ruby() 点击切换源代码

正在运行的 Ruby 解释器的路径。

# File lib/rubygems.rb, line 799
def self.ruby
  if @ruby.nil?
    @ruby = RbConfig.ruby

    @ruby = "\"#{@ruby}\"" if /\s/.match?(@ruby)
  end

  @ruby
end
ruby_api_version() 点击切换源代码

返回一个包含 Ruby 的 API 兼容版本的 String

# File lib/rubygems.rb, line 812
def self.ruby_api_version
  @ruby_api_version ||= RbConfig::CONFIG["ruby_version"].dup
end
ruby_engine() 点击切换源代码
# File lib/rubygems/defaults.rb, line 208
def self.ruby_engine
  RUBY_ENGINE
end
ruby_version() 点击切换源代码

当前运行的 Ruby 的 Gem::Version

# File lib/rubygems.rb, line 856
def self.ruby_version
  return @ruby_version if defined? @ruby_version
  version = RUBY_VERSION.dup

  if RUBY_PATCHLEVEL == -1
    if RUBY_ENGINE == "ruby"
      desc = RUBY_DESCRIPTION[/\Aruby #{Regexp.quote(RUBY_VERSION)}([^ ]+) /, 1]
    else
      desc = RUBY_DESCRIPTION[/\A#{RUBY_ENGINE} #{Regexp.quote(RUBY_ENGINE_VERSION)} \(#{RUBY_VERSION}([^ ]+)\) /, 1]
    end
    version << ".#{desc}" if desc
  end

  @ruby_version = Gem::Version.new version
end
rubygems_version() 点击切换源代码

当前运行的 RubyGems 的 Gem::Version

# File lib/rubygems.rb, line 875
def self.rubygems_version
  return @rubygems_version if defined? @rubygems_version
  @rubygems_version = Gem::Version.new Gem::VERSION
end
solaris_platform?() 点击切换源代码

此平台是否为 Solaris?

# File lib/rubygems.rb, line 1011
def self.solaris_platform?
  RUBY_PLATFORM.include?("solaris")
end
source_date_epoch() 点击切换源代码

返回 Gem.source_date_epoch_string 的值,作为 Time 对象。

这在整个 RubyGems 中用于启用可重复构建。

# File lib/rubygems.rb, line 1149
def self.source_date_epoch
  Time.at(source_date_epoch_string.to_i).utc.freeze
end
source_date_epoch_string() 点击切换源代码

如果设置了 SOURCE_DATE_EPOCH 环境变量,则返回其值。否则,返回与 SOURCE_DATE_EPOCH 格式相同的 Gem.source_date_epoch_string 首次调用时间。

注意(@duckinator):实现有点奇怪,因为我们想要

1. Make builds reproducible by default, by having this function always
   return the same result during a given run.
2. Allow changing ENV['SOURCE_DATE_EPOCH'] at runtime, since multiple
   tests that set this variable will be run in a single process.

如果你简化了这个函数,并且很多测试失败,这很可能是由于上面的第 2 点。

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

# File lib/rubygems.rb, line 1130
def self.source_date_epoch_string
  # The value used if $SOURCE_DATE_EPOCH is not set.
  @default_source_date_epoch ||= Time.now.to_i.to_s

  specified_epoch = ENV["SOURCE_DATE_EPOCH"]

  # If it's empty or just whitespace, treat it like it wasn't set at all.
  specified_epoch = nil if !specified_epoch.nil? && specified_epoch.strip.empty?

  epoch = specified_epoch || @default_source_date_epoch

  epoch.strip
end
sources() 点击切换源代码

返回一个包含远程 gem 源的 Array。如果源列表为空,则使用 default_sources

# File lib/rubygems.rb, line 884
def self.sources
  source_list = configuration.sources || default_sources
  @sources ||= Gem::SourceList.from(source_list)
end
sources=(new_sources) 点击切换源代码

需要能够设置源,而无需调用 Gem.sources.replace,因为这会导致无限循环。

DOC: 此注释不是关于方法本身的文档,它更像是关于实现的代码注释。

# File lib/rubygems.rb, line 896
def self.sources=(new_sources)
  if !new_sources
    @sources = nil
  else
    @sources = Gem::SourceList.from(new_sources)
  end
end
spec_cache_dir() 点击切换源代码
# File lib/rubygems.rb, line 395
def self.spec_cache_dir
  paths.spec_cache_dir
end
state_file() 点击切换源代码

用户状态文件标准位置的路径。

# File lib/rubygems/defaults.rb, line 140
def self.state_file
  @state_file ||= File.join(Gem.state_home, "gem", "last_update_check")
end
state_home() 点击切换源代码

用户状态目录标准位置的路径。

# File lib/rubygems/defaults.rb, line 161
def self.state_home
  @state_home ||= ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state")
end
suffix_pattern() 点击切换源代码

可 require 路径后缀的 glob 模式。

# File lib/rubygems.rb, line 907
def self.suffix_pattern
  @suffix_pattern ||= "{#{suffixes.join(",")}}"
end
suffix_regexp() 点击切换源代码

可 require 路径后缀的 Regexp

# File lib/rubygems.rb, line 914
def self.suffix_regexp
  @suffix_regexp ||= /#{Regexp.union(suffixes)}\z/
end
suffixes() 点击切换源代码

可 require 路径的后缀。

# File lib/rubygems.rb, line 935
def self.suffixes
  @suffixes ||= ["",
                 ".rb",
                 *%w[DLEXT DLEXT2].map do |key|
                   val = RbConfig::CONFIG[key]
                   next unless val && !val.empty?
                   ".#{val}"
                 end].compact.uniq
end
time(msg, width = 0, display = Gem.configuration.verbose) { || ... } 点击切换源代码

使用调试 UI 输出打印提供的代码块运行所需的时间。

# File lib/rubygems.rb, line 956
def self.time(msg, width = 0, display = Gem.configuration.verbose)
  now = Time.now

  value = yield

  elapsed = Time.now - now

  ui.say format("%2$*1$s: %3$3.3fs", -width, msg, elapsed) if display

  value
end
try_activate(path) 点击切换源代码

尝试激活包含 path 的 gem。如果激活成功或不需要激活(因为它已经激活),则返回 true。如果在 gem 中找不到路径,则返回 false。

# File lib/rubygems.rb, line 187
def self.try_activate(path)
  # finds the _latest_ version... regardless of loaded specs and their deps
  # if another gem had a requirement that would mean we shouldn't
  # activate the latest version, then either it would already be activated
  # or if it was ambiguous (and thus unresolved) the code in our custom
  # require will try to activate the more specific version.

  spec = Gem::Specification.find_by_path path
  return false unless spec
  return true if spec.activated?

  begin
    spec.activate
  rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
    spec_by_name = Gem::Specification.find_by_name(spec.name)
    if spec_by_name.nil?
      raise e
    else
      spec_by_name.activate
    end
  end

  true
end
ui() 点击切换源代码

延迟加载 DefaultUserInteraction 并返回默认 UI。

# File lib/rubygems.rb, line 971
def self.ui
  require_relative "rubygems/user_interaction"

  Gem::DefaultUserInteraction.ui
end
use_gemdeps(path = nil) 点击切换源代码

path 中查找 gem 依赖文件,如果找到,则激活文件中的 gem。如果找不到文件,则会引发 ArgumentError

如果未提供 path,则使用 RUBYGEMS_GEMDEPS 环境变量,但如果找不到文件,则不会引发异常。

如果 path 为 “-”,RubyGems 会从当前工作目录向上搜索 gem 依赖文件(gem.deps.rb、Gemfile、Isolate),并在找到第一个文件时激活其中的 gems。

你可以在 rubygems 启动时自动执行此操作。要启用此功能,请将 RUBYGEMS_GEMDEPS 环境变量设置为你的 gem 依赖文件路径或 “-” 以在父目录中自动发现。

注意:在多用户系统上启用自动发现可能会导致在不受你控制的目录中使用时执行任意代码。

# File lib/rubygems.rb, line 1070
def self.use_gemdeps(path = nil)
  raise_exception = path

  path ||= ENV["RUBYGEMS_GEMDEPS"]
  return unless path

  path = path.dup

  if path == "-"
    Gem::Util.traverse_parents Dir.pwd do |directory|
      dep_file = GEM_DEP_FILES.find {|f| File.file?(f) }

      next unless dep_file

      path = File.join directory, dep_file
      break
    end
  end

  unless File.file? path
    return unless raise_exception

    raise ArgumentError, "Unable to find gem dependencies file at #{path}"
  end

  ENV["BUNDLE_GEMFILE"] ||= File.expand_path(path)
  require_relative "rubygems/user_interaction"
  require "bundler"
  begin
    Gem::DefaultUserInteraction.use_ui(ui) do
      Bundler.ui.silence do
        @gemdeps = Bundler.setup
      end
    ensure
      Gem::DefaultUserInteraction.ui.close
    end
  rescue Bundler::BundlerError => e
    warn e.message
    warn "You may need to `bundle install` to install missing gems"
    warn ""
  end
end
use_paths(home, *paths) 点击切换源代码

使用 homepaths 值为 Gem.dirGem.path。主要用于单元测试以提供环境隔离。

# File lib/rubygems.rb, line 981
def self.use_paths(home, *paths)
  paths.flatten!
  paths.compact!
  hash = { "GEM_HOME" => home, "GEM_PATH" => paths.empty? ? home : paths.join(File::PATH_SEPARATOR) }
  hash.delete_if {|_, v| v.nil? }
  self.paths = hash
end
user_dir() 点击切换源代码

用户主目录中的 gems 路径。

# File lib/rubygems/defaults.rb, line 103
def self.user_dir
  gem_dir = File.join(Gem.user_home, ".gem")
  gem_dir = File.join(Gem.data_home, "gem") unless File.exist?(gem_dir)
  parts = [gem_dir, ruby_engine]
  parts << RbConfig::CONFIG["ruby_version"] unless RbConfig::CONFIG["ruby_version"].empty?
  File.join parts
end
user_home() 点击切换源代码

用户的 home 目录。

# File lib/rubygems/defaults.rb, line 96
def self.user_home
  @user_home ||= find_home
end
win_platform?() 点击切换源代码

这是一个 Windows 平台吗?

# File lib/rubygems.rb, line 992
def self.win_platform?
  if @@win_platform.nil?
    ruby_platform = RbConfig::CONFIG["host_os"]
    @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
  end

  @@win_platform
end
write_binary(path, data) 点击切换源代码

在所有平台上以二进制模式安全地写入文件。

# File lib/rubygems.rb, line 763
def self.write_binary(path, data)
  open_file(path, "wb") do |io|
    io.write data
  end
rescue Errno::ENOSPC
  # If we ran out of space but the file exists, it's *guaranteed* to be corrupted.
  File.delete(path) if File.exist?(path)
  raise
end

私有类方法

already_loaded?(file) 点击切换源代码
# File lib/rubygems.rb, line 1285
def already_loaded?(file)
  $LOADED_FEATURES.any? do |feature_path|
    feature_path.end_with?(file) && default_gem_load_paths.any? {|load_path_entry| feature_path == "#{load_path_entry}/#{file}" }
  end
end
default_gem_load_paths() 点击切换源代码
# File lib/rubygems.rb, line 1291
def default_gem_load_paths
  @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1].map do |lp|
    expanded = File.expand_path(lp)
    next expanded unless File.exist?(expanded)

    File.realpath(expanded)
  end
end
find_home() 点击切换源代码

查找用户的 home 目录。

# File lib/rubygems/defaults.rb, line 81
def self.find_home
  Dir.home.dup
rescue StandardError
  if Gem.win_platform?
    File.expand_path File.join(ENV["HOMEDRIVE"] || ENV["SystemDrive"], "/")
  else
    File.expand_path "/"
  end
end
find_spec_for_exe(name, exec_name, requirements) 点击切换源代码
# File lib/rubygems.rb, line 242
def self.find_spec_for_exe(name, exec_name, requirements)
  raise ArgumentError, "you must supply exec_name" unless exec_name

  dep = Gem::Dependency.new name, requirements

  loaded = Gem.loaded_specs[name]

  return loaded if loaded && dep.matches_spec?(loaded)

  specs = dep.matching_specs(true)

  specs = specs.find_all do |spec|
    spec.executables.include? exec_name
  end if exec_name

  unless spec = specs.first
    msg = "can't find gem #{dep} with executable #{exec_name}"
    raise Gem::GemNotFoundException, msg
  end

  spec
end