我正在用Ruby编写内部DSL。为此,我需要以编程方式创建命名类和嵌套类。这样做的最佳方法是什么?我认为有两种方法可以做到这一点:
Class.new
创建一个匿名类,然后使用define_method
向其添加方法,最后调用const_set
将它们作为命名常量添加到某个命名空间。eval
我已经测试了第一种方式并且它有效,但是对Ruby来说是新手,我不确定将类作为常量是正确的方法。
还有其他更好的方法吗?如果没有,上述哪一项更可取?
答案 0 :(得分:26)
如果你想创建一个带有动态名称的类,你必须完全按照你所说的去做。但是,您不需要使用define_method
。您只需将一个块传递给初始化类的Class.new
即可。这在语义上与class
/ end
的内容相同。
请记住const_set
,要认真对待该范围内的接收者(self
)。如果你想要全局定义的类,你需要在TopLevel模块上调用const_set
(它的名称和细节因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)
...
答案 1 :(得分:5)
您实际上不需要使用const_set
。可以将Class.new
的返回值分配给
一个常量,Class.new
的块是class_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>
答案 2 :(得分:4)
应该是这样的
a_new_class = Class.new(Object) do
attr_accessor :x
def initialize(x)
@x = x
end
end
SomeModule = Module.new
SomeModule.const_set("ClassName", a_new_class)
c = SomeModule::ClassName.new(10)