2012-05-30 42 views
20

这似乎并不是一件很难做的事情。以编程方式确定是否安装了某个宝石,然后安装它,如果不是的话

我想要一个ruby脚本,指出系统上当前是否安装了某个gem(任何版本和/或特定的版本规范)(如果没有,则会安装它)。

是的,我知道在某些情况下,bundler很棒。相信我,我有一个奇怪的原因,我不想使用捆绑软件。我真的很想以编程方式询问当地的宝石回购。

编程安装的一种方法就是将其当作gem install

但我不能设法找出一个可靠的方法以编程方式询问以查看是否安装了特定的宝石,不与外壳,不能带有rubygem API,没什么好看的。

我是否缺少它?

回答

19
# 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 

最近RubyGems的版本提供了一个安装程序的API,这样反而脱壳而出的gem命令你也可以使用:

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

不过,我不知道,如果Gem.install方面您的.gemrc文件。

查询安装的宝石有很多有用的方法(请参阅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方法实际加载的宝石的哈希,或通过require
+1

正是我所期待的完美答案,感谢提供几个API方法的例子,而不仅仅是一个。 rubygems ruby​​ code api很难得到一个概述性的理解,谢谢你的例子! – jrochkind

0

我不知道这是否是一个最佳实践或没有,但:

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

...在IRB为我工作。

+1

我寻找一种不涉及命令行外壳的解决方案,但可以用ruby代码完成。接受的答案是这样的 – jrochkind

16

最后的答案是好的,但是这是一个小更精确:

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

仅匹配命名为redis宝石,而不是其他的宝石一样redis-native_hash,或别的东西。

我见过这种做法的另一种方法是尝试要求宝石。

begin 
    require 'some_crazy_gem' 
rescue LoadError 
    `gem install some_crazy_gem` 
    #... 
end 
+0

是的,我会说“不,没有任何宝石开始'redis'”,但我想你的正则表达式与它的空间捕捉到了吗?还有一点让人惊讶的是,做到这一点同样不容易。例如,没有像'gem list'这样的命令,但它只返回完全匹配而不是子字符串? – jrochkind

+1

你也可以尝试'gem哪个宝石名称'。如果响应以ERROR开头,则不在那里。 –

+0

不错,这也不错。现在,如果只有一种方法来检查特定版本的特定宝石! rubygems对于所有这些东西都没有可靠的ruby API,这让人感到很疯狂,而且每个人都会采取屏幕刮取外壳。 – jrochkind

相关问题