要覆盖子类中的类常量,可以执行以下操作:
class Foo
CONST = [:foo, :baz]
def self.const
self::CONST
end
end
class Bar < Foo
CONST = [:foo, :bar]
end
print Foo.const # [:foo, :baz]
print Bar.const # [:foo, :bar]
这可以按预期工作。问题是当我尝试从类方法中调用它时,例如在使用define_method
:
class Foo
CONST = [:foo, :baz]
def self.const
self::CONST
end
self.const.each do |c|
define_method("#{c}?") {
"#{c} exists"
}
end
end
foo = Foo.new
print foo.baz? # baz exists.
bar = Bar.new
print bar.bar? # undefined method `bar?'
如何重写类常量,以便在这种情况下定义正确的方法bar?
,而不必复制子类中的代码?有没有使用类变量而不是类常量的DRY方法呢?
答案 0 :(得分:3)
因为define_method在词法范围内运行,即它在Foo类定义的主体中是内联的,所以没有任何东西可以使它在Bar中运行。
class Foo
CONST = [:foo, :baz]
def self.define_const_methods(const)
const.each do |c|
define_method("#{c}?") { "#{c} exists" }
end
end
define_const_methods(CONST)
end
class Bar < Foo
CONST = [:foo, :bar]
define_const_methods(CONST)
end
这应该可以解决问题。所以你在它的词法范围内调用Foo类末尾的define_const_methods。而且你也可以在任何继承它的类上调用它。继承类应该找到它自己的常量版本。
但这非常难看,所以你可以完全省去常量,只需使用define_const_methods来定义它们。就像ActiveRecord定义关联方法(has_one,has_many等)时一样。那么你可以把它简化为;
class Foo
def self.define_my_methods(meths)
meths.each do |c|
define_method("#{c}?") { "#{c} exists" }
end
end
define_my_methods [:foo, :baz]
end
class Bar < Foo
define_my_methods [:foo, :bar]
end