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

澄清 - 我不想加载库。我只想检查它是否可用,因此所有 rescue LoadError 解决方案都无法帮助我。此外,我不关心宝石本身是否有效,只是它是否已安装。

有帮助吗?

解决方案

恕我直言,最好的方法是尝试加载/要求GEM并拯救Exception,正如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?('somegem')

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

Gem.available?(/-?rcov$/)

使用 Gem:查看Gem API文档: :规范:: 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.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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top