有没有办法通过 Gem 模块检查当前是否安装了某些 gem?从 ruby 代码,而不是通过执行'gem list'......
澄清一下-我不想加载库。我只想检查它是否可用,所以所有rescue LoadError
解决方案都对我没有帮助。我也不关心 gem 本身是否可以工作,只关心它是否已安装。
仅在 Ruby 1.9.3 中还有:
Gem.available?('somegem')
您也可以使用正则表达式。如果我想允许 'rcov' 和 GitHub 变体,如 'relevance-rcov',这很方便:
Gem.available?(/-?rcov$/)
查看 Gem API 文档,使用Gem::Specification::find_all_by_name来测试 gem 可用性似乎是合理的。
if Gem::Specification::find_all_by_name('gemname').any?
do stuff
end
find_all_by_name
总是返回一个数组(规范对象),而不是find_by_name
如果找不到匹配项则引发异常。
恕我直言,最好的方法是尝试加载/要求 GEM 并拯救异常,正如 Ray 已经展示的那样。挽救 LoadError 异常是安全的,因为它不是由 GEM 本身引发的,而是 require 命令的标准行为。
您也可以改用 gem 命令。
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
gem 命令与 require 命令的行为相同,但有一些细微差别。AFAIK,它仍然尝试自动加载主 GEM 文件。
挖掘 rubygems.rb 文件(第 310 行)我发现了以下执行
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?
它可以为您提供一些关于如何在不实际加载库的情况下进行脏检查的提示。
自从 Gem.available? 已弃用(啊!),您必须再次救援(双重 aaargh)。是的,如果找不到 gem,find_by_name 会抛出异常。因此,为了与较旧的 rubygems 向后兼容,常见的解决方案似乎是:
def gem_available?(name)
Gem::Specification.find_by_name(name)
rescue Gem::LoadError
false
rescue
Gem.available?(name)
end
请注意,新方法允许您传递特定版本以查看是否已加载:
Gem::Specification.find_by_name('rails', '3.0.4')
你可以:
begin
require "somegem"
rescue LoadError
# not installed
end
但是,这不会告诉您该模块是通过 gem 还是其他方式安装的。
我使用此代码,它运行顺利。
def gem_available?(gem_name, version = nil)
version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
false
end
假设您安装了机架 1.9.1。
puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false
在这里的任何地方都没有看到这个,但您也可以将模糊版本字符串传递给find_by_name
and find_all_by_name
:
Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?