2012-02-24 25 views
2

我使用的模塊,命名空間和要動態填充這些帶班,如:如何在Ruby中動態更改嵌套?

module Module1 
    # ... 
end 

module Module2 
    # ... 
end 

[Module1, Module2].each do |the_module| 
    the_module.module_eval do 
    class ApiTest < ActiveSupport::TestCase 
     # ... 
    end 
    end 
end 

module_eval會的工作,但它確實改變排料,保持外一個。結果,包含的常量不會嵌套在模塊中。

原動機是產生相同測試爲它自己的模塊中的每個包含不同的API實現。

回答

1

這裏的另一種選擇(請注意「自我::」)

module Module1 
    # ... 
end 

module Module2 
    # ... 
end 

[Module1, Module2].each do |the_module| 
    the_module.module_eval do 
    class self::ApiTest < ActiveSupport::TestCase 
     # ... 
    end 
    end 
end 
+0

這顯然是贏家。 – qertoip 2012-02-25 09:36:43

1

您需要使用const_set

module Bar; end 
module Baz; end 

[Bar, Baz].each do |mod| 
    mod.const_set("Foo", Class.new do 
    def hello 
     "Hello world!" 
    end 
    end) 
end 

Bar::Foo.new.hello # => "Hello world!" 
Baz::Foo.new.hello # => "Hello world!" 

如果新類需要一個超類,你可以把它作爲參數傳遞給Class.new

0

我相信我已經找到了一種方法來做到這一點。

klass = Class.new(String) 
klass.class_eval do 
    def custom?; return true; end 
end 
Module1.module_exec do 
const_set :Custom, klass 
end 

Two::Custom.new.custom? 
#=> true 

Class::new第一個參數正在SuperClass

0

(繼承)我沒有測試過,但也許這樣的事情?

[Module1, Module2].each do |the_module| 
    the_module.const_set("ApiTest", Class.new(ActiveSupport::TestCase) do 
    # ... 
    end) 
end 
0
# Get ourselves a clean, top-level binding. 
def main_binding 
    binding 
end 

module ModuleUtils 
    module ModuleMethods ; end 
    self.extend ModuleMethods 

    module ModuleMethods 
    # Get a binding with a Module.nesting list that contains the 
    # given module and all of its containing modules as described 
    # by its fully qualified name in inner-to-outer order. 
    def module_path_binding(mod) 
     raise ArgumentError.raise(
     "Can't determine path nesting for a module with a blank name" 
    ) if mod.name.to_s.empty? 
     m, b = nil, main_binding 
     mod.name.split('::').each do |part| 
     m, b = 
     eval(
      "[ #{part} , #{part}.module_eval('binding') ]", 
      b 
     ) 
     end 
     raise "Module found at name path not same as specified module" unless m == mod 
     b 
    end 
    end 
end 

然後,您可以在您要使用ModuleUtils.module_path_binding(<some-module>)任何嵌套模塊上下文中執行代碼來獲得一個綁定,你可以作爲eval()的第二個參數傳遞。

查看更多在https://gist.github.com/2051705