2011-11-13 8 views
7

Estoy tratando de usar dos gemas para acceder a Amazon Web Services (AWS). Uno es Amazon 'aws-sdk', el otro es 'amazon-ec2'. Estoy usando el segundo ya que el aws-sdk no cubre la sección cloudwatch de los servicios de Amazon.Cargue dos módulos Ruby/gemas con el mismo nombre

El problema es que ambos se cargan en el mismo espacio de nombres.

require 'aws-sdk'   # aws-sdk gem 
require 'AWS'    # amazon-ec2 gem 

config = {:access_key_id => 'abc', :secret_key => 'xyz'} 

# start using the API with aws-sdk 
ec2 = AWS::EC2.new(config) 

# start using the API for anazon-ec2 
cw = AWS::Cloudwatch::Base.new(config) 

Ahora bien, esto es comprensible tiros un error en la última línea que el módulo de AWS está apuntando a la primera biblioteca requerida, en este caso AWS-SDK.

NameError: uninitialized constant AWS::Cloudwatch 

Entonces, ¿es posible que cargue uno de esos en otro espacio de nombres? Algo como

require 'aws-sdk', 'AWS_SDK' 
require 'AWS', 'AWS_EC2' 

ec2 = AWS_SDK::EC2.new(config) 
cw = AWS_EC2::Cloudwatch::Base.new(config) 

¿O hay otro truco que podría usar aquí?

Gracias

Respuesta

1

En Ruby, módulos con el mismo nombre de diferentes gemas no reemplazan entre sí. Si una gema implementa

module AWS 
    class Foo 
    end 
end 

y otros implementos

module AWS 
    class Bar 
    end 
end 

y así lo requieran tanto, el resultado final será con un módulo de AWS que contiene tanto una clase Foo y una barra de clase (a menos que la segunda lo hace algo realmente complicado como no definir explícitamente nada de lo que ya está presente en el módulo, antes de definir sus propias cosas, lo cual es muy poco probable). Siempre que la segunda gema no redefina los métodos en la primera gema (o intente utilizar un módulo como clase o viceversa), ambos deberían funcionar bien. Creo que puedes estar buscando la solución incorrecta.

Edit: Y, de hecho, lo que sucede para mí (en un entorno con solo estas gemas presentes (aws-sdk 1.2.3 y amazon-ec2 0.9.17) y el código exacto que enumeró arriba) es exactamente eso :

.rvm/gems/[email protected]/gems/amazon-ec2-0.9.17/lib/AWS/EC2.rb:2: EC2 is not a module (TypeError) 

Podría ser que un error es tragada en algún lugar y que el módulo de AWS :: CloudWatch no se ha definido, simplemente porque la inicialización de la gema sale mal?

+0

Gracias. Parece que hay una redefinición de clase/módulo en esas dos bibliotecas. Por ejemplo, AWS :: EC2 :: Instance es un módulo en amazon-ec2 y una clase en aws-sdk. ¿Alguna idea de cómo podría usar ambas bibliotecas? – Jon

+1

No creo que sea posible utilizar estos dos en el mismo intérprete de Ruby. Como probablemente no quiera cambiar a la gema que soporta Cloudwatch o tomarla para tomar el código que implementa el soporte de Cloudwatch de una gema e integrarlo en la otra, creo que su mejor opción es poner las cosas de Cloudwatch en un intérprete/proceso de Ruby separado y llámalo desde tu proceso 'principal' a través de DRb. Eso es razonablemente sencillo. Utilizo esa técnica en el trabajo para comunicarme entre un proceso de Ruby y un proceso de JRuby que aprovecha algunas bibliotecas de Java. – Confusion

+0

Creo que esa es la ruta a la que me dirijo. Gracias – Jon

1

Creo que he encontrado una solución que funciona, permítanme ilustrarlo con un ejemplo. Supongamos que tenemos a los archivos y a.rb b.rb que definen el mismo módulo con conflictos de nombres reales:

#file a.rb 
module A 
    def self.greet 
    puts 'A' 
    end 
end 

#file b.rb 
module A 
    def self.greet 
    puts 'other A' 
    end 
end 

Si tiene que requerir los dos, la siguiente parece hacer el truco:

require_relative 'a' 
TMP_A = A.dup 
A.greet # => A 
TMP_A.greet # => A 
require_relative 'b' 
TMP_A2 = A 
A.greet # => other A 
TMP_A2.greet # => other A 
TMP_A.greet # => A 

Sin la dup, TMP_A también apuntará a la A definido en b.rb después de la require_relative, pero el dup se asegurará de que una copia verdadera se produce en lugar de simplemente manteniendo una referencia al módulo.

Cuestiones relacionadas