20

这似乎不是一件难事。

我想要一个 ruby​​ 脚本,它可以确定系统上当前是否安装了某个 gem(任何版本和/或某个版本规范)(无论在哪里gem list),如果没有,则安装它。

是的,我知道在某些情况下 bundler 很擅长。相信我,我有一个案例,出于奇怪的原因,我不想使用 bundler。我真的很想以编程方式询问本地 gem 存储库。

以编程方式安装的一种方法是gem install,当然。

但是我无法找到一种可靠的方法来以编程方式询问是否安装了特定的 gem,而不是使用外壳,而不是使用 ruby​​gem api,而不是任何东西。

我错过了吗?

4

4 回答 4

20
# The version requirements are optional.
# You can also specify multiple version requirements, just append more at the end
gem_name, *gem_ver_reqs = 'json', '~> 1.8.0'
gdep = Gem::Dependency.new(gem_name, *gem_ver_reqs)
# find latest that satisifies
found_gspec = gdep.matching_specs.max_by(&:version)
# instead of using Gem::Dependency, you can also do:
# Gem::Specification.find_all_by_name(gem_name, *gem_ver_reqs)

if found_gspec
  puts "Requirement '#{gdep}' already satisfied by #{found_gspec.name}-#{found_gspec.version}"
else
  puts "Requirement '#{gdep}' not satisfied; installing..."
  # reqs_string will be in the format: "> 1.0, < 1.2"
  reqs_string = gdep.requirements_list.join(', ')
  # multi-arg is safer, to avoid injection attacks
  system('gem', 'install', gem_name, '-v', reqs_string)
end

最新的 ruby​​gems 版本提供了一个安装程序 API,因此gem您也可以使用以下命令,而不是使用该命令:

# using the same "gdep" variable as above
Gem.install gem_name, gdep.requirement

但是,我不确定是否Gem.install尊重您的.gemrc文件。

有很多有用的方法可以查询已安装的 gem(参见rdocs)。一些可能会有所帮助:

  • Gem::Specification.find_all_by_name
  • Gem::Requirement#satisfied_by?(gem_version_instance)
  • Gem::Specification#satisfies_requirement?(gem_dependency_instance)
  • Gem.loaded_specs- 您通过该gem方法或通过该方法实际加载的 gem 的哈希值require
于 2013-08-02T16:15:27.417 回答
18

最后一个答案很好,但这更精确一点:

`gem install redis` unless `gem list`.lines.grep(/^redis \(.*\)/)

仅匹配名为 的 gem redis,而不匹配其他 gem redis-native_hash,如 或其他。

我看到的另一种方法是尝试要求 gem。

begin
  require 'some_crazy_gem'
rescue LoadError
  `gem install some_crazy_gem`
  #...
end
于 2012-05-30T21:23:41.820 回答
4

检查是否安装了比特定版本更新的 gem。

PROMPT> gem list nakamoto -i -v ">=1.2.3"
true
于 2019-07-02T13:20:31.330 回答
-1

我不知道这是否是最佳实践,但是:

list = `gem list`
`gem install builder` unless list.include? "builder"

... 在 irb 为我工作。

于 2012-05-30T20:57:22.640 回答