2012-05-30 6 views
20

Esto no parece que sería algo difícil de hacer.determinan programáticamente si se instala una gema determinada, y luego la instalan si no es

Quiero un script de ruby ​​que se dé cuenta si una gema determinada (cualquier versión, y/o cierta especificación de versión) está actualmente instalada en el sistema (donde sea que se vea gem list), y si no, la instala.

Sí, sé que en algunos casos el paquete es genial en eso. Créeme que tengo un caso en el que por razones raras no quiero usar bundler. Realmente quiero cuestionar programáticamente el repositorio de gemas local.

Una forma de instalar programmatially es simplemente pagarle al gem install, claro.

Pero no puedo encontrar una forma confiable de programar interrogar para ver si una gema en particular está instalada, no con shell out, no con rubygem api, nada.

¿Echas de menos?

Respuesta

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 

más recientes versiones RubyGems proporcionan una API de instalación, por lo que en lugar de los bombardeos a cabo al comando gem También es posible usar:

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

Sin embargo, no estoy seguro de si Gem.install aspectos su archivo .gemrc.

Hay una gran cantidad de métodos útiles para consultar las gemas instaladas (ver rdocs). Algunos de los que podrían ser útiles:

  • Gem::Specification.find_all_by_name
  • Gem::Requirement#satisfied_by?(gem_version_instance)
  • Gem::Specification#satisfies_requirement?(gem_dependency_instance)
  • Gem.loaded_specs - picadillo de las joyas en realidad se ha cargado mediante el método gem, o por require
+1

respuesta perfecta exactamente lo que estaba buscando, gracias por proporcionar ejemplos de varios métodos de API en lugar de solo uno. El rubygems ruby ​​code api es difícil de entender, ¡gracias por los ejemplos! – jrochkind

0

no tengo ni idea de si esto es una buena práctica o no, pero:

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

... trabajó para mí en el IRB.

+1

estaba buscando una solución que no implicara un shell para la línea de comando, pero podría hacerse en código ruby. la respuesta aceptada es tal – jrochkind

16

Última respuesta fue buena, pero esto es un poco más preciso:

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

Partidos solamente la gema llamada redis, y no otras joyas como redis-native_hash, o alguna otra cosa.

Otra forma en que he visto esto hecho es intentar requerir la gema.

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

Sí, iba a decir "No, ninguna gema está comenzando a 'redis'", pero supongo que tu expresión regular con el espacio en ella capta eso? Todavía me sorprende que no haya una manera menos hacky de hacer esto. Por ejemplo, no hay ningún comando como 'gema lista' pero que solo devuelve coincidencias exactas en lugar de subcadenas? – jrochkind

+1

También podrías probar 'gem which gem-name'. Si la respuesta comienza con ERROR, no está allí. –

+0

bueno, eso también está bien. ¡Ahora si hubiera una forma de verificar una versión específica de una gema específica! Es una especie de locura que rubygems no tenga una aplicación confiable de rubí para todo esto, y todos recurren a la pantalla raspando un caparazón. – jrochkind

Cuestiones relacionadas