2010-12-23 58 views
1

我只是在探索ruby,想知道向對象的類添加方法的理論可能性。例如,定義一個接受參數的方法,並將該方法添加到該參數的類(而不僅僅是參數對象本身)。事情是這樣的例子: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 

(對不起,如果我有語法錯誤/錯別字我真的很新本!)
通知我怎麼不叫上gammaAddHelloMethodTo但我希望你好是定義是因爲我將它添加到了類中。
這可能嗎?

回答

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_methodprivate,所以你需要使用反射來規避訪問限制:

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] 
1

你的例子(一旦你修復了一個小的語法錯誤)將類方法添加到類而不是實例方法。

要定義一個實例方法,你可以使用class_eval和定義方法,如果你在定義類的中間:

def AddHelloMethodTo param 
    param.class.class_eval do 
    def Hello 
     "Hello" 
    end 
    end 
end 

現在,該對象的類的所有以前的和未來的情況下,將有機會獲得到Hello方法。

+0

啊好吧,當我嘗試在`alpha.Hello`運行失敗,我錯過了別的嗎? http://pastie.org/1399724 – TJB 2010-12-23 04:04:53

+0

噢,對不起,這實際上是爲您的類添加一個類方法,而不是實例方法。讓我編輯我的答案。 – 2010-12-23 04:09:11

相關問題