[英]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.