2011-07-08 29 views
7

में कक्षा विधि का विस्तार करना मैं रूबी की मेटाप्रोग्रामिंग सुविधाओं के साथ खेल रहा हूं, और मुझे थोड़ा बालों का पता चल रहा है। मैं एक मॉड्यूल का उपयोग कर एक विधि कॉल लपेटने की कोशिश कर रहा हूँ। वर्तमान में, मैं यह कर रहा हूँ:मॉड्यूल

module Bar 
    module ClassMethods 
    def wrap(method) 
     class_eval do 
     old_method = "wrapped_#{method}".to_sym 
     unless respond_to? old_method 
      alias_method old_method, method 

      define_method method do |*args| 
      send old_method, *args 
      end 
     end 
     end 
    end 
    end 

    def self.included(base) 
    base.extend ClassMethods 
    end 
end 

class Foo 
    include Bar 

    def bar(arg = 'foo') 
    puts arg 
    end 

    wrap :bar 
end 

तीन सवाल:

  1. वहाँ विधि का नाम बदलने के बिना यह करने के लिए कोई तरीका है, तो के रूप में super के उपयोग की अनुमति के लिए? या कुछ क्लीनर/छोटा?

  2. क्या डिफ़ॉल्ट मान सेट करने का कोई साफ तरीका है?

  3. क्या wrap :bar को आगे बढ़ाने के लिए कोई साधन है?

+0

वास्तविक जीवन में मैं इसके लिए कक्षा विरासत का उपयोग करूंगा। –

+0

मैं भी, लेकिन मैं इस सब को समझने की कोशिश कर रहा हूं। :-) –

+0

संबंधित: http://stackoverflow.com/questions/6631182/difference-between-class-eval-and-instance-eval-in-a- मॉड्यूल –

उत्तर

6

1) क्लीनर/कम

module ClassMethods 
    def wrap(method) 
    old = "_#{method}".to_sym 
    alias_method old, method 
    define_method method do |*args| 
     send(old, *args) 
    end 
    end 
end 

class Foo 
    extend ClassMethods 

    def bar(arg = 'foo') 
    puts arg 
    end 

    wrap :bar 
end 

जहाँ तक मुझे पता के रूप में वहाँ कोई रास्ता नहीं है का नाम बदलने के बिना इस लक्ष्य को हासिल किया जा सके। आप define_method ब्लॉक के अंदर super पर कॉल करने का प्रयास कर सकते हैं। लेकिन सबसे पहले, पर define_method के भीतर से कॉल केवल तभी सफल होगा जब आप स्पष्ट रूप से तर्क निर्दिष्ट करते हैं, अन्यथा आपको कोई त्रुटि मिलती है। लेकिन अगर आप उदा। super(*args), self उस संदर्भ में फू का एक उदाहरण होगा। तो bar पर कॉल Foo के सुपर क्लास में जाएगा, जो नहीं मिला और अंत में एक त्रुटि हुई।

2) हाँ, जैसे इतना

define_method method do |def_val='foo', *rest| 
    send(old, def_val, *rest) 
end 

हालांकि, रूबी 1.8 में यह not possibledefine_method में एक ब्लॉक का उपयोग करना है, लेकिन यह 1.9 के लिए तय किया गया है। यदि आप 1.9 का उपयोग कर रहे हैं, तो आप इस

define_method method do |def_val='foo', *rest, &block| 
    send(old, def_val, *rest, &block) 
end 

3) दुर्भाग्य से भी उपयोग कर सकते हैं। alias_method को इनपुट के रूप में लेने वाली विधियों के अस्तित्व की आवश्यकता होती है। चूंकि रूबी विधियों को अस्तित्व में लाया जाता है क्योंकि उन्हें पार्स किया जाता है, wrap कॉल bar की परिभाषा के बाद रखा जाना चाहिए अन्यथा alias_method अपवाद उठाएगा।

संबंधित मुद्दे