70 ruby metaprogramming class dynamic
如何使用名称在Ruby中动态定义类?
我知道如何动态创建一个没有名称的类使用类似的东西:
dynamic_class = Class.new do
def method1
end
end
Run Code Online (Sandbox Code Playgroud)
但是你不能指定一个类名.我想用名称动态创建一个类.
这是我想要做的一个例子,但当然它实际上并不起作用.
(注意,我不是创建类的实例而是创建类定义)
class TestEval
def method1
puts "name: #{self.name}"
end
end
class_name = "TestEval"
dummy = eval("#{class_name}")
puts "dummy: #{dummy}"
dynamic_name = "TestEval2"
class_string = """
class #{dynamic_name}
def method1
end
end
"""
dummy2 = eval(class_string)
puts "dummy2: #{dummy2}" # doesn't work
Run Code Online (Sandbox Code Playgroud)
实际产量:
dummy: TestEval
dummy2:
Run Code Online (Sandbox Code Playgroud)
期望的输出:
dummy: TestEval
dummy2: TestEval2
Run Code Online (Sandbox Code Playgroud)
================================================== ====
答:使用sepp2k方法的完全动态解决方案
dynamic_name = "TestEval2"
Object.const_set(dynamic_name, Class.new) # If inheriting, use Class.new( superclass )
dummy2 = eval("#{dynamic_name}")
puts "dummy2: #{dummy2}"
Run Code Online (Sandbox Code Playgroud)
sep*_*p2k 126
类的名称只是引用它的第一个常量的名称.
即如果我这样做myclass = Class.new
,那么MyClass = myclass
这个班的名字就会变成MyClass
.但是,MyClass =
如果我在运行时之前不知道类的名称,我就无法做到.
因此,您可以使用Module#const_set
,它动态设置const的值.例:
dynamic_name = "ClassName"
Object.const_set(dynamic_name, Class.new { def method1() 42 end })
ClassName.new.method1 #=> 42
Run Code Online (Sandbox Code Playgroud)
Wil*_*ins 32
我也一直在搞乱这个.在我的情况下,我试图测试ActiveRecord :: Base的扩展.我需要能够动态创建一个类,并且因为活动记录基于类名查找表,所以该类不能是匿名的.
我不确定这是否有助于你的情况,但这就是我想出的:
test_model_class = Class.new(ActiveRecord::Base) do
def self.name
'TestModel'
end
attr_accessor :foo, :bar
end
Run Code Online (Sandbox Code Playgroud)
就ActiveRecord而言,定义self.name就足够了.我猜这个实际上可以在一个类不能匿名的情况下工作.
(我刚读过sepp2k的回答,我认为他的回答更好.无论如何,我会留在这里.)