रूबी mixins और सुपर विधियों को बुलाओ

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

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

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

मेरी समस्या यह है कि मेरे पास मेरे किसी भी मिश्रण में after_initialize हो सकता है, इसलिए मुझे एक सुपर कॉल शामिल करना होगा यह सुनिश्चित करना शुरू करें कि अन्य मिश्रण 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

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

0
ro fr bn

4 उत्तर

सुपर विधि मौजूद है या नहीं, यह जांचने के बजाय, आप इसे परिभाषित कर सकते हैं

class ActiveRecord::Base
    def after_initialize
    end
end

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

0
जोड़ा
@yaauie - यकीन है, अगर मैं mon.inpe से पहले raise 'ओह नहीं' डाल सकता था? (: after_initialize) बंदरपैच से पहले, लेकिन यह उदाहरण को समझने में कठिन होगा ... यह इतना आसान है सभी किनारे के मामलों का विवरण देने में पकड़े जाने के लिए जो वास्तविक पाठ यहां है (केवल आधार विधि को पैच करें) शोर में खो जाएगा।
जोड़ा लेखक Orion Edwards, स्रोत
डाउनवॉटेड क्योंकि यह एक सामान्य समाधान नहीं है। मुद्दा यह है कि आप नहीं जानते कि सुपर मौजूद है या नहीं, इसलिए ActiveRecord :: बेस # को बंद करने के बाद ActiveRecord :: बेस # अस्तित्व में प्रारंभ करने के बाद, आप एक बिंदु बनाते हैं जहां आपका कोड टूट जाएगा यदि ActiveRecord आधार # after_initialize जोड़ता है, या इसकी धैर्य बदल जाती है ; यदि यह परिभाषित किया गया है तो सशर्त रूप से इसे कॉल करने के लिए यह बहुत ही कठिन है।
जोड़ा लेखक yaauie, स्रोत
बंदरगाह एक सामान्य समाधान नहीं है और नहीं करना चाहिए? सामान्य रूप में ? प्रोत्साहित रहो। एक उत्तर जिसमें एक ऑफ-ऑफ मोनकीपैच शामिल है जो हो सकता है काम करने के लिए होता है, अनावश्यक रूप से जटिल और नाजुक कोड की ओर जाता है, खासकर यदि आपके पास विरासत श्रृंखला तक सभी तरह का नियंत्रण नहीं है।
जोड़ा लेखक yaauie, स्रोत

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

alias_method_chain also has the benefit of creating named versions of the after_initialize method, meaning you can customize the call order in those rare cases that it matters. Otherwise, you're at the mercy of whatever order the including class includes the mixins.

later:

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

0
जोड़ा

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

0
जोड़ा

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

super if defined?(super)

यहाँ एक उदाहरण है:

class A
end

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

B.new.t
0
जोड़ा