Verifique a disponibilidade de Ruby Gem
Pergunta
Existe uma maneira de verificar se alguma jóia está actualmente instalado, através do módulo Gem? A partir do código Ruby, não por 'lista gem' execução ...
Para esclarecer - eu não quero carregar a biblioteca. Eu só quero verificar se ele está disponível, por isso, todas as soluções rescue LoadError
não me ajudar. Também eu não me importo se o próprio gem vai funcionar ou não, unicamente se ele está instalado.
Solução
IMHO a melhor maneira é tentar carga / exigem que o GEM e resgatar a exceção, como Ray já mostrou. É seguro para resgatar a exceção LoadError porque não é levantada pelo próprio GEM mas é o comportamento padrão do comando exigem.
Você também pode usar o comando gem vez.
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
O comando gem tem o mesmo comportamento do comando requerem, com algumas pequenas diferenças. AFAIK, ele ainda tenta autoLoad o arquivo GEM principal.
Indo para o arquivo rubygems.rb (linha 310) eu encontrei o seguinte execução
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?
Pode fornecer-lhe algumas dicas sobre como fazer uma verificação suja sem realmente carregar a biblioteca.
Outras dicas
Há também:
Gem.available?('somegem')
Você pode usar expressões regex também. Handy se eu quiser permitir 'rcov' e GitHub variantes como 'relevância no rcov':
Gem.available?(/-?rcov$/)
Olhando para a documentação da API Gem, usando Gem: :. Specification :: find_all_by_name para teste de disponibilidade gem parece razoável
if Gem::Specification::find_all_by_name('gemname').any?
do stuff
end
find_all_by_name
sempre retorna uma matriz (Especificação de objetos), em oposição a find_by_name
que suscita uma excepção se for encontrada nenhuma correspondência.
Desde Gem.available? está obsoleta (argh!), você tem que salvar novamente (aaargh duplo). Sim, métodos find_by_name_ lança uma exceção se a jóia não foi encontrada. Assim, para ser compatível com versões anteriores com rubygems mais velhos, a solução comum parece ser:
def gem_available?(name)
Gem::Specification.find_by_name(name)
rescue Gem::LoadError
false
rescue
Gem.available?(name)
end
Note que o novo método permite que você passe uma versão específica para ver se que é carregado:
Gem::Specification.find_by_name('rails', '3.0.4')
Você pode:
begin
require "somegem"
rescue LoadError
# not installed
end
Este não seria, no entanto, dizer-lhe se o módulo foi instalado através de jóia ou algum outro meio.
Eu uso este código e funciona sem problemas.
def gem_available?(gem_name, version = nil)
version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
false
end
Exemplos de usar
Vamos supor que você acumular 1.9.1 instalado.
puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false