ruby - topacio - construir una gema rubí y especificar condicionalmente las dependencias
rubi piedra precio (3)
He investigado esto también y he llegado a la conclusión de que no es posible por diseño. Tener una sola ''mega gema'' para todas las plataformas provoca el problema de no saber si una plataforma es compatible hasta que la gema se descarga e instala. Una gema tendría que ser lo suficientemente inteligente como para determinar cuál es la forma correcta de instalar en función de la plataforma. Si una plataforma no es compatible en absoluto, la gema puede fallar horriblemente, abriendo una gran lata de gusanos. Antes de que se instalara una gema, se solía hacer una devolución de llamada por el mismo motivo, no hay magia para que una gema se instale correctamente. Algunas personas han pirateado esto utilizando mkmf, pero sugiero seguir la ruta desgastada de una gema por plataforma como la mejor solución.
Basado en esto, en un proyecto que construye una gema para ruby y jruby, tengo que crear manualmente cada gema y subirlas a RubyGem. Usar Jeweler es tan simple como especificar el Gemfile , pero tengo que reconstruir la especificación de la gema cada vez que empaco una gema. Bastante trivial cuando se admiten solo 2 plataformas, pero el proceso de compilación es tan sencillo que podría automatizarse para brindar soporte a múltiples plataformas.
Estoy trabajando en una gema que tiene que establecer dependencias condicionalmente cuando se instala la gema. He hecho algunas excavaciones
y parece que no estoy solo en esta necesidad.
Rubygems: ¿Cómo agrego la dependencia específica de la plataforma?
este es un hilo largo
http://www.ruby-forum.com/topic/957999
La única manera que puedo ver para agregar dependencias a una gema es usar el método add_dependency dentro de un bloque Gem :: Specifiction en un archivo .gemspec
Gem::Specification.new do |s|
# ... standard setup stuff
# conditionally set dependencies
s.add_dependency "rb-inotify", "~> 0.8.8" if RUBY_PLATFORM =~ /linux/i
s.add_dependency "rb-fsevent", "~> 0.4.3.1" if RUBY_PLATFORM =~ /darwin/i
s.add_dependency "rb-fchange", "~> 0.0.5" if RUBY_PLATFORM =~ /mswin|mingw/i
end
Basándome en todos los documentos e hilos que encontré en la red, habría esperado que si instala la gema en
- Linux, entonces, rb-inotify sería una dependencia y autoinstalado
- Mac - rb-fsevent se instalaría
- Windows - se instalaría rb-fchange
Sin embargo, parece que ese no es el caso. Las declaraciones "if" dentro del bloque se evalúan en el momento en que se construye y empaqueta la gema. Por lo tanto, si construye y empaqueta la gema en Linux, entonces, rb-inotify se agrega como una dependencia, Mac, luego, rb-fsevent, Windows - rb-fchange.
Todavía necesitando una solución, busqué en el código de los rubygems y parece que la siguiente es una gran idea de lo que sucede.
- Construye todo tu código para tu gema: foo.gem
- crear un archivo foo.gemspec
- construir, empaquetar y lanzar la gema a un servidor de gemas como rubygems.org
- que todos sepan
- los desarrolladores lo instalan localmente a través de: gem install foo
- El archivo foo.gem se descarga, se desempaqueta e instala. Todas las dependencias están instaladas también.
- Todo debería estar listo y podemos comenzar usando la gema.
Parece que cuando la gema se crea y libera, el archivo foo.gemspec se carga y el bloque Gem :: Specification se evalúa y convierte a YAML, se comprime como metadata.gz y se incluye en foo.gem. El código ruby se comprime en data.tar.gz y también se incluye. Cuando la gema se instala en la máquina del desarrollador local, el YAML se extrae de metadata.gz y se convierte nuevamente en un bloque Gem :: Specification, sin embargo, no se vuelve a convertir al bloque original.
En su lugar, verá algo como lo siguiente:
Gem::Specification.new do |s|
if s.respond_to? :specification_version then
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new(''1.2.0'') then
s.add_runtime_dependency(%q<rb-inotify>, ["~> 0.8.8"])
else
s.add_dependency(%q<rb-inotify>, ["~> 0.8.8"])
end
else
s.add_dependency(%q<rb-inotify>, ["~> 0.8.8"])
end
end
De acuerdo. Por lo tanto, tengo una visión general del proceso, sin embargo, eso no cambia mi deseo de crear una gema única y especificar condicionalmente las dependencias para un rango de objetivos de SO.
Si alguien tiene una solución que no sea la creación de múltiples archivos .gemspec para cada sistema operativo de destino ... ¡Soy todo lo que oigo!
Nunca lo he hecho yo mismo, pero hay algunas gemas que están disponibles en versiones específicas de la plataforma: http://rubygems.org/gems/libv8/versions
por lo que entiendo, es solo una cuestión de nombres, que puede configurarse configurando la opción de plataforma de su gemspec. Eche un vistazo al documento: http://guides.rubygems.org/specification-reference/#platform=
También me he topado con este problema en el pasado. La única solución que pude encontrar fue crear una tarea de Rake para instalar las dependencias. Por supuesto, en esa etapa, es posible que desee dejar que el usuario descubra por sí mismo qué joya le falta en función del mensaje de error que está recibiendo. En mi caso, había varias dependencias dependientes de la plataforma para instalar, por lo que no era una opción.
Rakefile:
task :install do |t|
require ''./lib/library/installer''
Library::Installer.install
end
Instalador
module Library::Installer
require ''rubygems/dependency_installer''
def self.install
installer = Gem::DependencyInstaller.new
dependency = case RUBY_PLATFORM
when /darwin/i then ["rb-fsevent", "~> 0.4.3.1"]
when /linux/i then ["rb-inotify", "~> 0.8.8"]
when /mswin|mingw/i then ["rb-fchange", "~> 0.0.5"]
end
installer.install(*dependency)
end
Luego, el usuario puede usar la rake install
para instalar las dependencias apropiadas.
La instalación de dependencia condicional (no solo basada en la plataforma, sino también basada en la entrada del usuario, por ejemplo) le falta cruelmente a RubyGems. ¡Esperemos que se implemente en el futuro!