Pregunta

¿Hay alguna forma de verificar si alguna gema está instalada actualmente, a través del módulo Gem? Desde el código ruby, no ejecutando 'lista de gemas' ...

Para aclarar: no quiero cargar la biblioteca. Solo quiero verificar si está disponible, por lo que todas las soluciones rescue LoadError no me ayudan. Además, no me importa si la gema en sí funcionará o no, solo si está instalada.

¿Fue útil?

Solución

En mi humilde opinión, la mejor manera es intentar cargar / requerir el GEM y rescatar la excepción, como Ray ya ha demostrado. Es seguro rescatar la excepción LoadError porque no es generada por el propio GEM, pero es el comportamiento estándar del comando require.

También puedes usar el comando gem en su lugar.

begin
  gem "somegem"
  # with requirements
  gem "somegem", ">=2.0"
rescue Gem::LoadError
  # not installed
end

El comando gem tiene el mismo comportamiento que el comando require, con algunas pequeñas diferencias. AFAIK, todavía intenta cargar automáticamente el archivo GEM principal.

Excavando en el archivo rubygems.rb (línea 310) encontré la siguiente ejecución

matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?

Puede proporcionarle algunas sugerencias sobre cómo hacer un cheque sucio sin cargar realmente la biblioteca.

Otros consejos

También hay:

Gem.available?('somegem')

También puedes usar expresiones regex. Útil si quiero permitir variantes 'rcov' y GitHub como 'relevancia-rcov':

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

Mirando la documentación de la API Gem, usando Gem: : Especificación :: find_all_by_name para probar la disponibilidad de gemas parece razonable.

if Gem::Specification::find_all_by_name('gemname').any?
  do stuff
end

find_all_by_name siempre devuelve una matriz (de objetos de Especificación), en lugar de find_by_name que genera una excepción si no se encuentra ninguna coincidencia.

¿Desde Gem.available? está en desuso (¡argh!), tienes que rescatar nuevamente (doble aaargh). Sí, find_by_name produce una excepción si no se encuentra la gema. Por lo tanto, para ser compatible con versiones anteriores de rubygems, la solución común parece ser:

def gem_available?(name)
   Gem::Specification.find_by_name(name)
rescue Gem::LoadError
   false
rescue
   Gem.available?(name)
end

Tenga en cuenta que el nuevo método le permite pasar una versión específica para ver si está cargada:

Gem::Specification.find_by_name('rails', '3.0.4')

Podrías:

begin
  require "somegem"
rescue LoadError
  # not installed
end

Sin embargo, esto no le diría si el módulo se instaló a través de gem u otro medio.

Uso este código y funciona sin problemas.

def gem_available?(gem_name, version = nil)
  version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
  false
end

Ejemplos de uso

Supongamos que tiene instalado el rack 1.9.1.

puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top