2011-06-16 25 views
8

में method_missing युक्त मॉड्यूल मैं मॉड्यूल है कि विधि लापता विस्तार की एक जोड़ी है। इसी तरह, ObjectB.new.goodbye_xxx आउटपुट "Goodbye, xxx"respond_to? भी काम करता है, उदाहरण के लिए ObjectA.new.respond_to? :hello_there सत्य लौटें।कैसे रचना के लिए गहरे लाल रंग का

बहरहाल, यह बहुत अच्छी तरह से जब आप दोनों SaysHello और SaysGoodbye उपयोग करना चाहते हैं काम नहीं करता: सही ढंग से

class ObjectC 
    include SaysHello 
    include SaysGoodbye 
end 

ObjectC.new.goodbye_aaa जबकि काम करता है, ObjectC.new.hello_a अजीब कार्य करता है:

> ObjectC.new.hello_aaa 
Hello, hello_aaa 
NoMethodError: private method `method_missing' called for nil:NilClass 
    from test.rb:22:in `method_missing' (line 22 was the super.method_missing line in the SaysGoodbye module) 

यह सही ढंग से आउटपुट, फिर एक त्रुटि फेंकता है। respond_to? सही नहीं है, ObjectC.new.respond_to? :hello_a झूठा देता है।

अंत में, इस वर्ग को जोड़ने:

class ObjectD 
    include SaysHello 
    include SaysGoodbye 

    def respond_to?(method) 
     super.respond_to?(method) || !!(method.to_s =~ /^lol/) 
    end 


    def method_missing(method, *args, &block) 
     if (method.to_s =~ /^lol/) 
      puts "Haha, #{method}" 
     else 
      super.method_missing(method, *args, &block) 
     end 
    end 
end 

भी अजीब कार्य करता है। ObjectD.new.lol_zzz काम करता है, हालांकि ObjectD.new.hello_a and ObjectD.new.goodbye_t दोनों सही स्ट्रिंग आउटपुट के बाद नाम अपवाद फेंक देते हैं। respond_to? भी हैलो और अलविदा विधियों के लिए विफल रहता है।

क्या यह सब ठीक से काम करने का कोई तरीका है? method_missing, मॉड्यूल और super कैसे बातचीत कर रहे हैं इसका एक स्पष्टीकरण भी वास्तव में उपयोगी होगा।

संपादित करें: कोरयवर्ड ने समस्या को हल किया है, अगर मैं परिभाषित सभी विधियों में super.<method-name>(args...) के बजाय सुपर का उपयोग करता हूं, तो प्रोग्राम सही तरीके से काम करता है। मुझे समझ में नहीं आता कि यह क्यों है, इसलिए मैंने What does super.<method-name> do in ruby?

+0

शामिल मॉड्यूल विरासत श्रृंखला के लिए जोड़ रहे; वे विधियों को ओवरराइड या प्रतिस्थापित नहीं करते हैं। तो यदि प्रत्येक method_missing सुपर कॉल करता है, तो अंत में वे सभी को बुलाया जाएगा। नीचे मेरा जवाब देखें। – ChrisPhoenix

उत्तर

5

पर एक और सवाल पूछा जब आप किसी विधि को फिर से परिभाषित करते हैं, तो आप एक विधि को फिर से परिभाषित करते हैं; अवधि।

जब आप method_missing विधि परिभाषा के साथ दूसरा मॉड्यूल शामिल करते हैं तो आप क्या कर रहे हैं पहले परिभाषित method_missing ओवरराइड कर रहे हैं। इससे पहले कि आप इसे फिर से परिभाषित करने से पहले इसे अलियासिंग करके इसे चारों ओर रख सकें, लेकिन आप इसके साथ देखना चाहेंगे।

इसके अलावा, मुझे नहीं पता कि आप super.method_missing क्यों कॉल कर रहे हैं। एक बार आपकी method_missing परिभाषा चाल से बाहर है, आपको रूबी को यह पता होना चाहिए कि यह कॉल को संभालने के तरीके की तलाश में श्रृंखला को जारी रख सकता है, बस super पर कॉल करके (तर्क पारित करने या विधि का नाम निर्दिष्ट करने की आवश्यकता नहीं है)।

सुपर बारे (अपडेट)

जब आप फोन super रूबी अप विरासत श्रृंखला विधि लागू की अगली परिभाषा की तलाश में पर जारी है, और अगर यह एक पाता है यह कॉल और प्रतिक्रिया देता है। जब आप super.method_missing पर कॉल करते हैं तो आप super() की प्रतिक्रिया पर method_missing विधि को कॉल करते हैं।

इस (कुछ मूर्ख) उदाहरण लें:

class Sauce 
    def flavor 
    "Teriyaki" 
    end 
end 

# yes, noodles inherit from sauce: 
# warmth, texture, flavor, and more! ;) 
class Noodle < Sauce 
    def flavor 
    sauce_flavor = super 
    "Noodles with #{sauce_flavor} sauce" 
    end 
end 

dinner = Noodle.new 
puts dinner.flavor  #=> "Noodles with Teriyaki sauce" 

आप देख सकते हैं कि सुपर किसी भी अन्य की तरह एक विधि है, यह सिर्फ पर्दे के पीछे कुछ जादू है। यदि आप super.class पर कॉल करते हैं तो आप String देख रहे हैं, क्योंकि "तेरियाकी" एक स्ट्रिंग है।

अब समझ में आ गया है?

+0

लेकिन दूसरे मॉड्यूल को आयात करने से पहले मॉड्यूल के method_missing को ओवरराइड नहीं किया गया था, अन्यथा ObjectC.new.hello_a ने हैलो, हैलो_ए (प्लस एक नेमरर) आउटपुट नहीं किया होगा। super.method_missing (...) के बजाय सुपर का उपयोग करने से वास्तव में समस्या हल हो गई है, सभी method_missing कॉल और answer_to? कॉल अब सही ढंग से काम करते हैं। मुझे समझ में नहीं आता क्यों। –

+0

@nanothief: मैंने रूबी में 'सुपर' कैसे काम करता है इस बारे में और अधिक समझाया है (उम्मीद है)। मुझे लगता है कि यह आपके लिए चीजों को साफ़ करेगा। – coreyward

+0

धन्यवाद, यह समस्या थी जो मैं सुपर के साथ कर रहा था। मैं मान रहा था कि super.method माता-पिता वर्ग पर विधि को कॉल कर रहा था, सुपरक्लास पर वर्तमान विधि को कॉल करने के परिणाम पर विधि को कॉल नहीं कर रहा था। –

1

http://www.perfectline.ee/blog/activerecord-method-missing-with-multiple-inheritance

यह लेख वास्तव में यह कैसे काम करता बताते हैं: प्रत्येक नए मॉड्यूल के ऊपर लिख या तरीकों को प्रतिस्थापित नहीं करता - इसके बजाय, अपने तरीकों विरासत श्रृंखला में डाला जाता है। यही कारण है कि प्रत्येक method_missing से सुपर कॉलिंग अंततः सभी method_missing की कॉल करता है।

कक्षा विरासत श्रृंखला में सबसे कम है, और अंतिम जोड़ा मॉड्यूल कक्षा के समीप है।

तो: कर्नेल में

class Foo 
    include A 
    include B 
end 

परिणाम -> A -> बी -> फू

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