这是最接近你所拥有的。我冒昧地将其更改为标准 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]