2008-08-14 16 views
34

ठीक है, इसलिए मैं डुप्लिकेशंस को हटाने के प्रयास में अपने छोटे रेल ऐप में अपना कोड दोबारा कर रहा हूं, और सामान्य रूप से मेरे जीवन को आसान बना देता हूं (जैसा कि मुझे एक आसान जीवन पसंद है)। इस रिफैक्टरिंग का एक हिस्सा, कोड को स्थानांतरित करना है जो मेरे दो मॉडलों के लिए एक मॉड्यूल में आम है जिसमें मैं इसे शामिल कर सकता हूं।रूबी मिश्रक और सुपर विधियों को बुलाएं

अब तक तो अच्छा। ऐसा लगता है कि यह काम करने जा रहा है, लेकिन मैंने अभी एक समस्या को मारा है कि मुझे यकीन नहीं है कि कैसे घूमना है। मॉड्यूल (जिसे मैंने भेजने योग्य कहा है), सिर्फ वह कोड होगा जो फ़ैक्सिंग, ई-मेलिंग या दस्तावेज़ के पीडीएफ को प्रिंट करता है। इसलिए, उदाहरण के लिए, मेरे पास एक खरीद आदेश है, और मेरे पास आंतरिक बिक्री आदेश हैं (कल्पनात्मक रूप से आईएसओ को संक्षेप में)।

समस्या मैं मारा गया है, कि मैं चाहता हूँ कुछ चर initialised (जो लोग सही लिखें नहीं है के लिए प्रारंभ: पी), के बाद वस्तु भरी हुई है तो मैं after_initialize हुक का उपयोग कर रहा है। कोई समस्या नहीं ... जब तक मैं कुछ और मिश्रण जोड़ने शुरू नहीं करता।

समस्या मेरे पास है

, मैं एक after_initialize मेरी mixins में से किसी एक में हो सकता है है, इसलिए मुझे यकीन है कि अन्य mixin after_initialize कॉल कहा जाता हो बनाने के लिए शुरू में एक सुपर कॉल शामिल करने की ज़रूरत । जो महान है, जब तक कि मैं सुपर कॉलिंग समाप्त नहीं करता और मुझे कोई त्रुटि मिलती है क्योंकि कॉल करने के लिए कोई सुपर नहीं है।

यहाँ मामले में एक छोटे से उदाहरण दिया गया है, मैं काफी भ्रमित नहीं किए गए हैं:

class Iso < ActiveRecord::Base 
    include Shared::TracksSerialNumberExtension 
    include Shared::OrderLines 
    extend Shared::Filtered 
    include Sendable::Model 

    validates_presence_of :customer 
    validates_associated :lines 

    owned_by    :customer 
    order_lines    :despatched # Mixin 

    tracks_serial_numbers :items # Mixin 

    sendable :customer      # Mixin 

    attr_accessor :address 

    def initialize(params = nil) 
    super 
    self.created_at ||= Time.now.to_date 
    end 
end 

तो, अगर mixins में से हर एक एक after_initialize फोन है, एक सुपर कॉल के साथ, मैं कैसे रोक सकता कि अंतिम सुपर त्रुटि उठाने से कॉल करें? मैं यह कैसे जांच सकता हूं कि इसे कॉल करने से पहले सुपर विधि मौजूद है?

उत्तर

40

आप इस का उपयोग कर सकते हैं:

class A 
end 

class B < A 
    def t 
    super if defined?(super) 
    puts "Hi from B" 
    end 
end 

B.new.t 
0

बजाय पता चल सके कि सुपर विधि मौजूद है, तो आप सिर्फ यह

class ActiveRecord::Base 
    def after_initialize 
    end 
end 

यह मेरा परीक्षण में काम करता है, और अपने मौजूदा कोड के किसी भी तोड़ने नहीं करना चाहिए, क्योंकि अपने सभी अन्य वर्गों जो इसे परिभाषित परिभाषित कर सकते हैं इस विधि को चुपचाप ओवरराइड कर रहे हैं

+1

downvoted क्योंकि यह एक सामान्य समाधान नहीं है:

super if defined?(super) 

यहाँ एक उदाहरण है। मुद्दा यह है कि आप नहीं जानते कि सुपर मौजूद है या नहीं, इसलिए ActiveRecord :: बेस # को बंद करने के बाद ActiveRecord :: बेस # अस्तित्व में प्रारंभ करने के बाद, आप एक बिंदु बनाते हैं जहां आपका कोड टूट जाएगा यदि ActiveRecord आधार # after_initialize जोड़ता है, या इसकी धैर्य बदल जाती है ; यदि यह परिभाषित किया गया है तो सशर्त रूप से इसे कॉल करने के लिए यह बहुत ही कठिन है। – yaauie

+0

@yaauie - निश्चित रूप से, अगर मैं monkeypatch से पहले विधियों को शामिल कर सकता हूं, तो मैं 'raise' ओह नहीं कर सकता था? (: बाद में शुरूआत करें), लेकिन यह उदाहरण को समझने में कठिन होगा ... पकड़ा जाना इतना आसान है सभी किनारे के मामलों का विवरण देने में कि वास्तविक पाठ यहां (केवल मूल विधि पैच करें) शोर में खो जाएगा। –

+1

बंदरगाह एक सामान्य समाधान नहीं है और सामान्य रूप से - प्रोत्साहित किया जाना चाहिए। एक उत्तर जिसमें एक-ऑफ मोनीकीपैच शामिल है जो * काम * हो सकता है, अनावश्यक रूप से जटिल और नाजुक कोड की ओर जाता है, खासकर यदि आपके पास विरासत श्रृंखला तक सभी तरह का नियंत्रण नहीं है। – yaauie

3

क्या आपने alias_method_chain को आजमाया है? आप मूल रूप से अपने सभी after_initialize कॉलों को जंजीर कर सकते हैं। यह एक सजावट की तरह कार्य करता है: प्रत्येक नई विधि कार्यक्षमता की एक नई परत जोड़ती है और बाकी को करने के लिए "ओवरराइड" विधि पर नियंत्रण को पास करती है।

3

वर्ग (बात यह है कि ActiveRecord::Base से विरासत है, जो, में यह मामला है Iso) इसलिए किसी भी alias_method_chain (या अन्य अलियासिंग कि मूल की बचत होती है) के अलावा अन्य समाधान का अपना after_initialize निर्धारित कर सकते हैं, सहित कोड अधिलेखन जोखिम। @ ओरियन एडवर्ड्स का समाधान सबसे अच्छा है जिसके साथ मैं आ सकता हूं। अन्य हैं, लेकिन वे दूर अधिक हैकिश हैं।

alias_method_chain को बाद में आरंभिक विधि के नामित संस्करण बनाने का लाभ भी है, जिसका अर्थ है कि आप उन दुर्लभ मामलों में कॉल ऑर्डर को कस्टमाइज़ कर सकते हैं। अन्यथा, आप कक्षा के मिश्रण सहित किसी भी आदेश की दया पर हैं।

बाद में:

मैं सभी कॉलबैक के डिफ़ॉल्ट खाली कार्यान्वयन बनाने के बारे में माणिक-ऑन-रेल-कोर मेलिंग सूची के लिए एक प्रश्न पोस्ट किया। बचत प्रक्रिया उन सभी के लिए जांचती है, इसलिए मुझे नहीं पता कि उन्हें वहां क्यों नहीं होना चाहिए। केवल नकारात्मक पक्ष अतिरिक्त खाली ढेर फ्रेम बना रहा है, लेकिन यह हर ज्ञात कार्यान्वयन पर बहुत सस्ता है।

2

तुम बस वहाँ में एक त्वरित सशर्त फेंक कर सकते हैं:

super if respond_to?('super') 

और आप ठीक होना चाहिए - कोई जोड़ने बेकार तरीकों; अच्छा और साफ।

+0

यह ** ** ** काम पर दिखाई नहीं देता है। respond_to? ('सुपर') हमेशा झूठी वापसी करेगा। – averell

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