[英]ruby monkey patching on the fly
有沒有辦法在實例化對象時實現猴子補丁?
當我打電話時:
a = Foo.new
在實例化實例之前,我想根據我將從數據存儲中讀取的信息擴展 Foo 類。 因此,每次我調用Foo.new
,將添加到該類實例的擴展Foo.new
動態更改。
tl;dr:可以向實例添加方法。
答:無法向實例添加方法。 Ruby 中的實例沒有方法。 但是每個實例都可以有一個單例類,可以在其中添加方法,然后這些方法只能在為該單例類創建的單個實例上可用。
class Foo
end
foo = Foo.new
def foo.bark
puts "Woof"
end
foo.bark
class << foo
def chew
puts "Crunch"
end
end
foo.chew
foo.define_singleton_method(:mark) do
puts "Widdle"
end
foo.mark
只是為對象定義單例方法的一些方法。
module Happy
def cheer
puts "Wag"
end
end
foo.extend(Happy)
foo.cheer
這采用了另一種方法,它將在繼承鏈中的單例類和真實類之間插入模塊。 這樣,模塊也可用於實例,但不能用於整個類。
你當然可以!
method_name_only_known_at_runtime = 'hello'
string_only_known_at_runtime = 'Hello World!'
test = Object.new
test.define_singleton_method(method_name_only_known_at_runtime) do
puts(string_only_known_at_runtime)
end
test.hello
#> Hello World!
在實例化實例之前,我想擴展
給定一個類Foo
,它在其initialize
方法中執行某些操作:
class Foo
attr_accessor :name
def initialize(name)
self.name = name
end
end
還有一個模塊FooExtension
想要改變這種行為:
module FooExtension
def name=(value)
@name = value.reverse.upcase
end
end
您可以通過prepend
修補它:
module FooPatcher
def initialize(*)
extend(FooExtension) if $do_extend # replace with actual logic
super
end
end
Foo.prepend(FooPatcher)
或者您甚至可以在調用initialize
之前通過提供您自己的new
類方法進行extend
:
class Foo
def self.new(*args)
obj = allocate
obj.extend(FooExtension) if $do_extend # replace with actual logic
obj.send(:initialize, *args)
obj
end
end
兩種變體產生相同的結果:
$do_extend = false
Foo.new('hello')
#=> #<Foo:0x00007ff66582b640 @name="hello">
$do_extend = true
Foo.new('hello')
#=> #<Foo:0x00007ff66582b280 @name="OLLEH">
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.