我正在探索ruby,并且想知道将一个方法添加到对象类的理论可能性。例如,定义一个接受参数的方法,并将方法添加到该参数的类中(而不仅仅是参数对象本身)。像这样的例子:
class SomeClass
end
class AnotherClass
end
alpha = SomeClass.new
beta = AnotherClass.new
def AddHelloMethodTo param
# This is where I'm trying to
# add a method to the class of the parameter
def param.class.Hello
"Hello"
end
end
AddHelloMethodTo alpha
AddHelloMethodTo beta
gamma = AnotherClass.new
alpha.Hello
beta.Hello
gamma.Hello
(对不起,如果我有语法错误/错别字,我真的很新!)
请注意我不会在AddHelloMethodTo
上调用gamma
,但我希望定义Hello,因为我已将其添加到类中。
这可能吗?
答案 0 :(得分:7)
这是你最接近的。我冒昧地将其更改为标准的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
方法对于它的论点,它将它添加到它的论据 class 。
但是,如果你像这样进行猴子修补,通常认为使用mixins是好习惯,从那以后,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]
答案 1 :(得分:1)
您的示例(一旦修复了一个小的语法错误)将类方法添加到类而不是实例方法。
要定义实例方法,可以使用class_eval
并定义方法,就好像您正在定义类一样:
def AddHelloMethodTo param
param.class.class_eval do
def Hello
"Hello"
end
end
end
现在,对象类的所有先前和未来实例都可以访问Hello
方法。