42

有没有办法通过 Gem 模块检查当前是否安装了某些 gem?从 ruby​​ 代码,而不是通过执行'gem list'......

澄清一下-我不想加载库。我只想检查它是否可用,所以所有rescue LoadError解决方案都对我没有帮助。我也不关心 gem 本身是否可以工作,只关心它是否已安装。

4

7 回答 7

38

仅在 Ruby 1.9.3 中还有:

Gem.available?('somegem')

您也可以使用正则表达式。如果我想允许 'rcov' 和 GitHub 变体,如 'relevance-rcov',这很方便:

Gem.available?(/-?rcov$/)
于 2009-09-15T01:52:57.823 回答
37

查看 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如果找不到匹配项则引发异常。

于 2012-12-04T21:00:26.807 回答
32

恕我直言,最好的方法是尝试加载/要求 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 文件。

挖掘 ruby​​gems.rb 文件(第 310 行)我发现了以下执行

matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?

它可以为您提供一些关于如何在不实际加载库的情况下进行脏检查的提示。

于 2009-06-23T12:38:44.380 回答
30

自从 Gem.available? 已弃用(啊!),您必须再次救援(双重 aaargh)。是的,如果找不到 gem,find_by_name 会抛出异常。因此,为了与较旧的 ruby​​gems 向后兼容,常见的解决方案似乎是:

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')
于 2011-09-17T14:46:32.003 回答
6

你可以:

begin
  require "somegem"
rescue LoadError
  # not installed
end

但是,这不会告诉您该模块是通过 gem 还是其他方式安装的。

于 2009-06-23T12:02:23.750 回答
1

我使用此代码,它运行顺利。

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
于 2014-08-19T11:50:54.553 回答
0

在这里的任何地方都没有看到这个,但您也可以将模糊版本字符串传递给find_by_nameand find_all_by_name

Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?
于 2019-10-12T16:49:03.143 回答