在Ruby中动态定义命名类
我正在用Ruby编写内部DSL。 为此,我需要以编程方式创建命名类和嵌套类。 这样做的最佳方法是什么? 我认为有两种方法可以做到这一点:
- 使用
Class.new
创建一个匿名类,然后使用define_method
向其添加方法,最后调用const_set
将它们作为命名常量添加到某个命名空间。 - 使用某种
eval
我已经测试了第一种方式并且它有效,但是对Ruby来说是新手,我不确定将类作为常量放置是正确的方法。
还有其他更好的方法吗? 如果没有,上述哪一项更可取?
如果你想创建一个具有动态名称的类,你必须完全按照你所说的去做。 但是,您不需要使用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) ...
你真的不需要使用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=> #
应该是这样的
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)