I'm trying to use two Gems to access Amazon Web Services (AWS). One is the Amazon 'aws-sdk', the other is 'amazon-ec2'. I'm using the second as the aws-sdk does not cover the cloudwatch section of the amazon services.
The issue is that both load into the same namespace.
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)
Now this understandably throws an error on the last line as the AWS module is pointing at the first required library, in this case aws-sdk.
NameError: uninitialized constant AWS::Cloudwatch
So, is it possible for me to load one of those into another namespace? Something like
require 'aws-sdk', 'AWS_SDK'
require 'AWS', 'AWS_EC2'
ec2 = AWS_SDK::EC2.new(config)
cw = AWS_EC2::Cloudwatch::Base.new(config)
Or is there another trick I could use here?
Thanks
In Ruby, modules with the same name from different gems don't replace each other. If one gem implements
module AWS
class Foo
end
end
and another implements
module AWS
class Bar
end
end
and you require them both, you will end up with an AWS module that contains both a class Foo and a class Bar (unless the second does something really tricky like explicitly undefining anything already present in the module, before defining its own stuff, which is very unlikely). As long as the second gem doesn't redefine any methods in the first gem (or attempts to use a module as a class or vice versa), they should both work fine. I think you may be looking for the wrong solution.
Edit: And in fact, what happens for me (in an environment with only these gems present (aws-sdk 1.2.3 and amazon-ec2 0.9.17) and the exact code you listed above) is exactly that:
.rvm/gems/ree-1.8.7-2011.03@ec2/gems/amazon-ec2-0.9.17/lib/AWS/EC2.rb:2: EC2 is not a module (TypeError)
Could it be that an error gets swallowed somewhere and that the module AWS::Cloudwatch hasn't been defined, simply because the initialization of the gem goes awry?
I think I've found a solution that works, let me illustrate it with an example. Suppose we have to files a.rb and b.rb that define the same module with actual name clashes:
#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
If you need to require both of them, the following seems to do the trick:
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
Without the dup
, TMP_A
will also point to the A
defined in b.rb after the require_relative
, but the dup
will ensure that a real copy is produced instead of simply holding a reference to the module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With