這是最接近你的。我把它更改爲標準的Ruby編碼風格的自由,但要注意的是,只有真正變化是add_hello_method_to_class_of
第一行:
class SomeClass; end
class AnotherClass; end
alpha = SomeClass.new
beta = AnotherClass.new
def add_hello_method_to_class_of(obj)
obj.class.send(:define_method, :hello) do
'Hello'
end
end
add_hello_method_to_class_of(alpha)
add_hello_method_to_class_of(beta)
gamma = AnotherClass.new
alpha.hello
beta.hello
gamma.hello
本來,你有
def obj.class.hello
這將工作,但它不會做你認爲它的作用。這將爲類對象本身添加一個單例方法,但它似乎假定它將添加一個實例方法。如果你想添加一個實例方法,你需要使用Module#define_method
這樣的:
obj.class.define_method(:hello)
除了Module#define_method
是private
,所以你需要使用反射來規避訪問限制:
obj.class.send(:define_method, :hello)
請注意,我也將方法的名稱從add_hello_method_to
更改爲add_hello_method_to_class_of
,因爲,那麼它不會不會將hello
方法添加到它的參數,它將它添加到它的參數他的論點類。但是,如果你像這樣做猴子修補,通常認爲使用mixin是一種很好的做法,因爲mixin會出現在對象的繼承鏈中,從而使得任何人都無法調試該代碼,這至少是一次戰鬥機會找出其中到底那個神祕hello
方法是從哪裏來的:
# file: hello_extension.rb
module HelloExtension
def hello
'Hello'
end
end
def add_hello_method_to_class_of(obj)
obj.class.send(:include, HelloExtension)
end
# some other file
require 'hello_extension'
class SomeClass; end
class AnotherClass; end
alpha = SomeClass.new
beta = AnotherClass.new
add_hello_method_to_class_of(alpha)
add_hello_method_to_class_of(beta)
gamma = AnotherClass.new
alpha.hello
beta.hello
gamma.hello
現在,你可以很容易地調試代碼:
gamma.class.ancestors
# => [AnotherClass, HelloExtension, Object, Kernel, BasicObject]
如果有人想知道其中hello
方法來從那以後,找出一個名爲HelloExtension
的mixin可能與它有關。而下面的標準的Ruby命名慣例,他們甚至不知道在一個名爲hello_extension.rb
你甚至可以做這個文件來:
gamma.method(:hello).source_location
# => ['hello_extension.rb', 3]
啊好吧,當我嘗試在`alpha.Hello`運行失敗,我錯過了別的嗎? http://pastie.org/1399724 – TJB 2010-12-23 04:04:53
噢,對不起,這實際上是爲您的類添加一個類方法,而不是實例方法。讓我編輯我的答案。 – 2010-12-23 04:09:11