具有类名的动态类定义

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)

  • 哇.对我来说似乎很奇怪(常量)赋值具有这种副作用. (3认同)

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的回答,我认为他的回答更好.无论如何,我会留在这里.)

  • 顺便说一句,您可以只为该类显式设置表名,如下所示:`self.table_name =“ my_things”` (2认同)