加载两个名称相同的Ruby Modules/Gems

Jon*_*Jon 7 ruby rubygems amazon-ec2 amazon-web-services

我正在尝试使用两个Gems来访问Amazon Web Services(AWS).一个是亚马逊'aws-sdk',另一个是'amazon-ec2'.我正在使用第二个,因为aws-sdk不包括亚马逊服务的cloudwatch部分.

问题是两者都加载到同一名称空间.

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) 
Run Code Online (Sandbox Code Playgroud)

现在,这可以理解地在最后一行引发错误,因为AWS模块指向第一个必需的库,在本例中为aws-sdk.

NameError: uninitialized constant AWS::Cloudwatch
Run Code Online (Sandbox Code Playgroud)

那么,我可以将其中一个加载到另一个命名空间中吗?就像是

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

ec2 = AWS_SDK::EC2.new(config)  
cw = AWS_EC2::Cloudwatch::Base.new(config) 
Run Code Online (Sandbox Code Playgroud)

或者我可以在这里使用另一种技巧吗?

谢谢

Con*_*ion 3

在 Ruby 中,来自不同 gem 的同名模块不会互相替换。如果一颗 gem 实现

module AWS
  class Foo
  end
end
Run Code Online (Sandbox Code Playgroud)

另一个实现

module AWS
  class Bar
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你同时需要它们,你最终会得到一个包含 Foo 类和 Bar 类的 AWS 模块(除非第二个模块做了一些非常棘手的事情,比如在定义自己的东西之前显式取消定义模块中已经存在的任何内容,即不太可能)。只要第二个 gem 不重新定义第一个 gem 中的任何方法(或尝试将模块用作类,反之亦然),它们都应该可以正常工作。我认为您可能正在寻找错误的解决方案。

编辑:事实上,对我来说发生的事情(在只有这些 gem 的环境中(aws-sdk 1.2.3 和 amazon-ec2 0.9.17)以及上面列出的确切代码)正是这样:

.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)
Run Code Online (Sandbox Code Playgroud)

是否会因为 gem 的初始化出错而在某处被吞没并且模块 AWS::Cloudwatch 尚未定义?

  • 我认为不可能在同一个 Ruby 解释器中同时使用这两者。由于您可能不想切换到支持 Cloudwatch 的 gem,或者不想从一个 gem 获取实现 Cloudwatch 支持的代码并将其集成到另一个 gem 中,所以我认为您最好的选择是将 Cloudwatch 内容放入其中在单独的 Ruby 解释器/进程中,并通过 DRb 从“主”进程中调用它。这是相当简单的。我在工作中使用该技术在 Ruby 进程和利用一些 Java 库的 JRuby 进程之间进行通信。 (2认同)