2014-01-16 39 views
6

在Ruby中,是否有方法在調用該類的任何其他方法時調用方法? 例如,如何在類的任何其他方法被調用時調用類的方法(Ruby)

class Car 
    def repair 
     puts "Repaired!" 
    end 
    def drive 
     # content 
    end 
    def checkup 
     # content 
    end 
end 

在這個例子中,如果我調用任何方法對Car一個實例,我應該始終調用repair方法。我如何在Ruby中執行此操作?

注意:我也repair調用內置的方法,太像Carinstance.class應該叫repair了。

+0

缺乏在每種方法中調用'repair'的問題嗎? – Kal

+0

是的。而對於像.class這樣的內置方法,它應該在那裏調用'repair'。 Car類只是我需要的一個例子。 – crownusa

+0

爲什麼你想要這個內置的方法? – Shoe

回答

7

我假設你想在Car的其他實例方法返回之後調用Car#repair。我看到您已經添加了其他方法也會調用repair的要求。我在最後添加了一些關於擴展它的內容以包含內置的實例方法。

我採取的方法是利用BasicObject#method_missing

class Car 
    def repair 
    puts "Repaired!" 
    end 

    def drive 
    puts "Drive!" 
    end 

    def checkup 
    puts "Checkup!" 
    end 

    def method_missing(m, *args) 
    if @@ims.key?(m) 
     ret = send(@@ims[m], *args) 
     repair 
     ret 
    else 
     super 
    end 
    end 

@@ims = instance_methods(false).each_with_object({}) do |m,h| 
    next if (m == :repair || m == :method_missing) 
    saved_name = "_#{m}" 
    alias_method saved_name, m 
    h[m] = saved_name 
    remove_method(m) 
    end    
end 

car = Car.new 

car.repair 
Repaired! 

car.drive 
Drive! 
Repaired! 

car.checkup # 
Checkup! 
Repaired! 

car.wash # => in `method_missing': undefined method `wash'... 

當類Car被解析,所有的實例方法已建成之後,可以進行以下操作我用一個例子來解釋:

instance_methods(false) # => [:repair, :drive, :checkup, :method_missing] 

each_with_object({})創建一個散列(最初爲空),由塊變量h(稍後會詳細介紹)引用。

next if (m == :repair || m == :method_missing) 

導致:repair:method_missing被跳過。

m => :drive,以下三個語句有效地重新命名:drive:_drive並添加:drive" => "_drive"到哈希h

each_with_object返回

@@ims = {:drive=>"_drive", :checkup=>"_checkup"} 

現在

instance_methods(false) # => [:repair, :method_missing, :_drive, :_checkup] 

因爲不再有一個方法:driveCar.new.drive調用method_missing(:drive)。後者發現@@ims有一個密鑰:drive,因此它使用send來調用:_drive,調用:repair並返回:_drive的返回值。如果method_missing通過的方法不是@@ims的密鑰,則調用super並引發異常。

在現在刪除的編輯中,我建議要包含內置的實例方法,只需要將instance_methods(false)更改爲instance_methods,但會警告可能出現意外的副作用。 @Kal指出,內置的實例方法不能被刪除,所以這種方法將無法工作。這也是一樣 - 不應該以這種方式惹惱Ruby。我顯然沒有測試我的主張。恥辱!

+0

輝煌!你可以修改它以使用'instance_methods(true)',因此它也包含內置方法嗎? – Kal

+0

@Kal,你的願望是我的命令。 –

+1

它看起來像remove_method(m)不適用於內置(繼承)方法。我收到錯誤「NameError:method'nil?'未在車中定義「。有時候可能會向OP建議,在Object類中使用方法並不是一個好主意,或者是否有解決方法? – Kal

1
class Car 
    def self.default_method 
     instance_methods(true).each do |meth| 
     alias_method meth, :repair 
     end 
    end 
    def initialize 
    self.class.default_method 
    end 

    def repair 
    puts "Repaired!" 
    end 
    def drive 
    # content 
    end 
    def checkup 
    # content 
    end 
end 

car = Car.new 

car.drive # => Repaired! 
car.checkup # => Repaired! 
car.class # => Repaired! 

注意,重新定義內置的方法生成一些警告:

# => untitled 5:6: warning: redefining `object_id' may cause serious problems 
# => untitled 5:6: warning: redefining `__send__' may cause serious problems 

編輯:哎呀,我得太快發佈此,並沒有發現問題。它調用repair,但不是原始方法。我知道這似乎太簡單了!我認爲我對此深表歉意。 :-)(注意:我認爲Cary的方法真的很聰明,它對你自己的方法有用,但是看起來他用內置方法達到了死衚衕,無論如何,它都會以某種方式改變方法你真的不應該嘗試使用內置方法)。

+0

嘿@Kal,我喜歡你的答案,我試了一下,除了一個問題外,它完美的工作:除了原來的方法內容外,我還想把'repair'叫做**。例如:'car.methods'應該調用'repair',但仍然應該返回一組方法,'car.class'應該調用'repair',除了返回類。謝謝你的幫助! – crownusa

+0

對不起,我提到我的答案在底部的編輯中無法正常工作。我發佈得太快,一開始沒有注意到,因爲驅動器和檢查方法不輸出任何內容。我也應該刪除評論「但它行得通!」,我現在要做。 :-) – Kal

相關問題