在Ruby中动态定义命名类

Lit*_*les 26 ruby dsl metaprogramming metaclass

我正在用Ruby编写内部DSL.为此,我需要以编程方式创建命名类和嵌套类.这样做的最佳方法是什么?我认为有两种方法可以做到这一点:

  1. 使用Class.new创建一个匿名类,然后使用define_method的方法添加到它,最后调用const_set将其添加为命名常量一些命名空间.
  2. 使用某种方式 eval

我已经测试了第一种方式并且它有效,但是对Ruby来说是新手,我不确定将类作为常量是正确的方法.

还有其他更好的方法吗?如果没有,上述哪一项更可取?

Dyl*_*kes 27

如果您想创建一个具有动态名称的类,您将必须完全按照您的说法进行操作.但是,您不需要使用define_method.您可以将块传递给Class.new初始化类的块.这在语义上与class/ 的内容相同end.

记住const_set,要认真对待self那个范围内的接收者().如果你想要全局定义的类,你需要调用const_setTopLevel模块(它的名称和细节因Ruby而异).

a_new_class = Class.new(Object) do
  attr_accessor :x

  def initialize(x)
    print #{self.class} initialized with #{x}"
    @x = x
  end
end

SomeModule.const_set("ClassName", a_new_class)

c = ClassName.new(10)

...
Run Code Online (Sandbox Code Playgroud)

  • 您能更具体地了解顶级模块的名称吗? (3认同)

Jul*_*lik 5

你真的不需要使用const_set.返回值Class.new可以分配给常量而块Class.newclass_eval.

class Ancestor; end
SomeClass = Class.new(Ancestor) do
  def initialize(var)
     print "#{self.class} initialized with #{var}"
  end
end
=> SomeClass
SomeClass.new("foo")
# SomeClass initialized with foo=> #<SomeClass:0x668b68>
Run Code Online (Sandbox Code Playgroud)

  • 这不会创建具有动态名称的类.SomeClass是静态确定的. (4认同)
  • 在您的示例中,您将新类定义为"SomeClass".您刚刚粘贴的示例与您的声明"您实际上不需要使用const_set"相矛盾.您需要使用它将某些东西绑定到模块常量. (2认同)