[英]Dynamically define a super method for an instance of a class in Ruby
假设我们有一个我们不能改变的类,
class C
def foo
super
puts "Low!"
end
end
我们需要动态地定义foo
方法,以便我们能够注入到 C 的祖先链中。 super
的行为必须特定于给定的对象,而不是类范围的。 我们将能够将该逻辑包含在一个匿名模块中(让我们暂时命名):
module M
def foo
puts "High!"
end
end
使用模块扩展C
的实例:
c = C.new
c.extend(M)
c.foo
# High!
将不起作用,因为我们将模块中的方法放在我们在类中定义的方法之前。 查看我们对象的祖先
c.singleton_class.ancestors
# => [#<Class:#<C:0x00005652be630b20>>, M, C, ...]
我想出了一个丑陋的解决方法,即在我们的单例类中重新定义我们类中的方法,即
c.define_singleton_method(:foo, c.class.instance_method(:foo))
c.foo
# High!
# Low!
虽然这有效(它有效吗?我已经测试了一段时间,似乎可以,但我不再确定),我想知道我是否遗漏了一些明显的东西,并且有一种更简单的方法来动态定义“超级" 类的实例的方法。
明确地说,我们希望能够用另一个模块扩展另一个C
实例,即
C.new.extend(Module.new do
def foo
puts "Medium!"
end
end).foo
# Medium!
# Low!
并使其输出不受其他实例的污染。
既然我知道您正在尝试解决某些第三方代码中的问题,我可以建议一个更合理的解决方案。 在下面的代码中,我认为B
和C
是由 gem 定义的,您不想更改它们的源代码,但是您想在C#foo
调用B#foo
的地方注入一些代码。
class B
def foo
puts "Highest!"
end
end
class C < B
def foo
super
puts "Low!"
end
end
module CE
def foo
super
foo_injected
end
end
C.include(CE)
module M
def foo_injected
puts "High!"
end
end
c = C.new
c.extend(M)
p c.singleton_class.ancestors
c.foo
输出是:
[#<Class:#<C:0x000055ce443366a8>>, M, C, CE, B, Object, Kernel, BasicObject]
Highest!
High!
Low!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.