2012-05-30 25 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

相關問題