如何在Ruby中动态更改嵌套?

如何在Ruby中动态更改嵌套?,ruby,module,namespaces,metaprogramming,nested,Ruby,Module,Namespaces,Metaprogramming,Nested,我使用模块作为名称空间,并希望用类动态填充它们,如: module Module1 # ... end module Module2 # ... end [Module1, Module2].each do |the_module| the_module.module_eval do class ApiTest < ActiveSupport::TestCase # ... end end end 模块1 # ... 结束 模块2 # ..

我使用模块作为名称空间,并希望用类动态填充它们,如:

module Module1
  # ...
end

module Module2
  # ...
end

[Module1, Module2].each do |the_module|
  the_module.module_eval do
    class ApiTest < ActiveSupport::TestCase
      # ...
    end
  end
end
模块1
# ...
结束
模块2
# ...
结束
[Module1,Module2]。每个do都是| u模块|
_module.module_eval do
类ApiTest
module_eval
可以工作,除非它不改变嵌套,保留外部嵌套。因此,包含的常量不会嵌套在模块中

最初的动机是为各自模块中包含的不同API实现生成相同的测试。

您需要使用:


如果新类需要一个超类,可以将其作为参数传递给。

我相信我已经找到了一种方法

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
的第一个参数是
超类
(继承自)

我还没有测试过,但可能是这样的

[Module1, Module2].each do |the_module|
  the_module.const_set("ApiTest", Class.new(ActiveSupport::TestCase) do
    # ...
  end)
end
这里还有另一个选项(注意“self:”)

模块1
# ...
结束
模块2
# ...
结束
[Module1,Module2]。每个do都是| u模块|
_module.module_eval do
类self::ApiTest
然后,您可以使用
ModuleUtils.module\u path\u binding()
在任何嵌套模块上下文中执行代码,以获得一个绑定,该绑定可以作为第二个参数传递给eval()

更多信息请访问

[Module1, Module2].each do |the_module|
  the_module.const_set("ApiTest", Class.new(ActiveSupport::TestCase) do
    # ...
  end)
end
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
# 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