前任留下了一个祖传代码,看着挺好的,通过一个 build 方法,就可以动态创建一个新的类。等到自己去实现第二个类的时候,出了问题。say 方法被覆盖了。第一感觉就是,类被重新打开,然后被覆写了。
class Base
def self.build (&block)
Class.new(self) do
yield
end
end
def base_method
puts 'base_method'
end
end
T = Base.build do
public
def say
puts 'T'
end
end
M = Base.build do
public
def say
puts 'M'
end
end
T.new.base_method
M.new.base_method
T.new.say
M.new.say
后来,在尝试打印 self 的时候,发现 block 是在顶级作用域 main 里面执行的。导致的结果就是,第二次会覆盖第一次的方法定义,而且所有地方都有这个方法,无论是类方法,还是实例方法。
T = Base.build do
p self
def say
puts 'T'
end
end
问题到这里,就是切换 context 的问题了。用 class_eval 可以切换 context 到新建的类执行代码块,进而定义实例方法。
class Base
def self.build (&block)
Class.new(self) do
class_eval @block
end
end
def base_method
puts 'base_method'
end
end
参考 https://stackoverflow.com/questions/19319138/dynamically-create-a-class-inherited-from-activerecord