2009-06-04 36 views
1

我想幹掉我的代碼,所以我正在編寫一種方法將某些方法推遲或委託給不同的對象,但只有當它存在時。這裏是基本的想法:我有Shipment < AbstractShipment可能有Reroute < AbstractShipmentShipment或它的Reroute可以有Delivery(或交付),但不是兩者。從別名方法調用超級方法

當我打電話shipment.deliveries,我希望它檢查,看它是否有重新路由第一。如果不是,那麼只需撥打AbstractShipmentdeliveries方法;如果是,則將該方法委派給重新路由。

我試圖與下面的簡單代碼:

module Kernel 
    private 
    def this_method 
     caller[0] =~ /`([^']*)'/ and $1 
    end   
end 

class Shipment < AbstractShipment 
    ... 

    def deferToReroute 
    if self.reroute.present? 
     self.reroute.send(this_method) 
    else 
     super 
    end 
    end 

    alias_method :isComplete?, :deferToReroute 
    alias_method :quantityReceived, :deferToReroute 
    alias_method :receiptDate, :deferToReroute 
end 

的Kernel.this_method僅僅是找出哪些方法被調用了便利。但是,調用super拋出

super: no superclass method `deferToReroute' 

我搜索了一下,發現this link其中討論,這是Ruby 1.8中的一個錯誤,但固定在1.9。不幸的是,我無法將此代碼升級到1.9,所以有人有任何解決方法的建議嗎?

感謝:-)

編輯:後一點看我的代碼,我意識到,我並不真的需要別名的所有的,我做的方法,我其實只需要覆蓋交貨方法,因爲其他三個實際稱之爲他們的計算。但是,自從我遇到過這個問題之後,我仍然很想知道你們的想法。

回答

2

而不是在這裏使用alias_method,你可能會得到更好的硬重寫這些方法,像這樣服務:

class Shipment < AbstractShipment 
    def isComplete? 
    return super unless reroute 
    reroute.isComplete? 
    end 
end 

,如果你發現你正在做的每類此的5-10倍,你可以把它更好像這樣:

class Shipment < AbstractShipment 
    def self.deferred_to_reroute(*method_names) 
    method_names.each do |method_name| 
     eval "def #{method_name}; return super unless reroute; reroute.#{method_name}; end" 
    end 
    end 
    deferred_to_reroute :isComplete?, :quantityReceived, :receiptDate 
end 

使用直EVAL提供good performance characteristics,並允許你有你的類定義中做一個簡單的聲明語法。

+0

太棒了!如果我已經玩了一段時間了,我會嘗試這樣的事情,因爲我一直在編寫一個類似的插件,但我懷疑它會一直很乾淨。非常感謝 :-) – 2009-06-05 13:24:48