Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रेल्स 5 Module#prepend पेश करता है: alias_method_chain को प्रतिस्थापित करना

रेल्स 4.2 की घोषणा में आगामी रेल्स 5 के बारे में कुछ दिलचस्प समाचार थे: इसके लिए शायद रूबी 2.2 की आवश्यकता होगी। जो इसे रूबी 2 की सभी अच्छी चीजों का लाभ उठाने वाला पहला रेल्स वर्जन बना देगा।

पोस्ट में गार्बेज-कलेक्टेड सिम्बल्स और कीवर्ड आर्ग्यूमेंट्स का उल्लेख किया गया था। लेकिन मेरे लिए, रूबी 2 की सबसे दिलचस्प विशेषताओं में से एक Module#prepend है।

alias_method_chain का अच्छा (और बुरा)

जब मैंने पहली बार रेल्स सीखा, तो alias_method_chain ने मेरा दिमाग पूरी तरह से उड़ा दिया। इसने वास्तव में दिखाया कि रूबी कितना लचीला हो सकता है।

सिर्फ कोड की एक लाइन के साथ, आप पूरी तरह से बदल सकते हैं कि एक मेथड कैसे काम करता है। आपको अपने इच्छित कोड को जोड़ने के लिए लाइब्रेरीज को हैक करने की आवश्यकता नहीं थी, आप बस इसे ऑन-द-फ्लाई जोड़ सकते थे। alias_method_chain ने मेरे जेम्स में पहले पैच का नेतृत्व किया, जिससे मेरे पहले पुल रिक्वेस्ट बने, जिससे मेरे पहले ओपन सोर्स योगदान बने।

लेकिन मंकी पैचिंग की तरह ही, alias_method_chain का अत्यधिक उपयोग किया गया, और इसकी समस्याएं स्पष्ट होने लगीं:

  • यह जो मेथड नाम उत्पन्न करता है वे भ्रमित करने वाले हैं, जिससे त्रुटियों को ढूंढना और डीबग करना कठिन हो जाता है। उदाहरण के लिए:
class Person
  def greeting
    "Hello"
  end
end

module GreetingWithExcitement
  def self.included(base)
    base.class_eval do
      alias_method_chain :greeting, :excitement
    end
  end

  def greeting_with_excitement
    "#{greeting_without_excitement}!!!!!"
  end
end

Person.send(:include, GreetingWithExcitement)

यदि Person#greeting में कोई त्रुटि थी, तो बैकट्रेस आपको बताएगा कि त्रुटि वास्तव में Person#greeting_without_excitement में हुई। लेकिन वह मेथड कहां परिभाषित है? मैं इसे कहीं नहीं देखता। आप कैसे जानते हैं कि बग वाला greeting मेथड कौन सा है? और मेथड नाम जितना अधिक आप चेन करते हैं उतने ही भ्रमित करने वाले हो जाते हैं।

  • यदि आप एक ही क्लास पर समान पैरामीटर्स के साथ alias_method_chain को दो बार कॉल करते हैं, तो आप स्टैक ओवरफ्लो का कारण बन सकते हैं। (क्या आप देख सकते हैं क्यों?) यह आमतौर पर नहीं होता है, जब तक आपके require स्टेटमेंट्स उन पथों के बारे में सुसंगत हैं जिनका वे उपयोग करते हैं। लेकिन यह सुपर कष्टप्रद है यदि आप अक्सर रेल्स कंसोल में कोड पेस्ट करते हैं।

  • और येहुदा काट्ज़ के ब्लॉग पोस्ट में वर्णित बाकी चीजें। इस पोस्ट ने बहुत सारे रेल्स डेवलपर्स को alias_method_chain को छोड़कर मॉड्यूल इनहेरिटेंस के पक्ष में शुरू करने के लिए मना लिया।

तो, इसका अभी भी उपयोग क्यों किया जाता है?

आप अधिकांश alias_method_chain को उन मेथड्स को एक मॉड्यूल में ओवरराइड करके, और उन मॉड्यूल्स को अपनी चाइल्ड क्लासेस में शामिल करके बदल सकते हैं। लेकिन यह केवल तभी काम करता है जब आप अपने सुपरक्लास को ओवरराइड करना चाहते हैं, न कि अपनी क्लास को। अर्थात:

class ParentClass
  def log
    puts "In parent"
  end
end

class ChildClass < ParentClass
  def log
    puts "In child"
    super
  end

  def log_with_extra_message
    puts "In child, with extra message"
    log_without_extra_message
  end

  alias_method_chain :log, :extra_message
end

यदि आप ChildClass.new.log चलाते हैं, तो आप देखेंगे:

In child, with extra message
In child
In parent

यदि आप alias_method_chain के बजाय मॉड्यूल्स का उपयोग करने की कोशिश करते हैं, तो आप आउटपुट प्राप्त कर सकते हैं:

In child
In child, with extra message
In parent

लेकिन आप ChildClass में log मेथड को बदले बिना मूल आउटपुट से मेल नहीं खा सकते। रूबी इनहेरिटेंस उस तरह काम नहीं करता। खैर, यह नहीं करता था।

रूबी 2.0 में क्या बदला?

रूबी 2.0 तक, एक क्लास के नीचे कोड जोड़ने का कोई तरीका नहीं था, केवल ऊपर। लेकिन prepend के साथ, आप एक क्लास में मेथड को एक मॉड्यूल से मेथड से ओवरराइड कर सकते हैं, और अभी भी super के साथ क्लास के कार्यान्वयन तक पहुंच सकते हैं। तो, हमारे पिछले उदाहरण का उपयोग करके, हम मूल आउटपुट के साथ प्राप्त कर सकते हैं:

class ParentClass
  def log
    puts "In parent"
  end
end

module ExtraMessageLogging
  def log
    puts "In child, with extra message"
    super
  end
end

class ChildClass < ParentClass
  prepend ExtraMessageLogging
  def log
    puts "In child"
    super
  end
end
In child, with extra message
In child
In parent

परफेक्ट।

यदि prepend अभी भी आपके सिर के चारों ओर लपेटना कठिन है, तो इसे ऐसा करने के रूप में सोचें:

class NewChildClass < ChildClass
  include ExtraMessageLogging
end
ChildClass = NewChildClass

सिवाय इसके कि यह आपके क्लास नामों के साथ खिलवाड़ नहीं करेगा, और यह पहले से मौजूद ऑब्जेक्ट्स को प्रभावित करता है।

(हां, आप रूबी में क्लास नामों को पुनः असाइन कर सकते हैं। नहीं, यह शायद एक महान विचार नहीं है।)

इसका रेल्स के लिए क्या मतलब है?

तो, alias_method_chain का उपयोग करने का अंतिम बहाना रूबी 2.0 में चला गया है। हम रेल्स में alias_method_chain के कुछ शेष उदाहरणों में से एक ले सकते हैं:

rails/activesupport/lib/active_support/core_ext/range/each.rb
require 'active_support/core_ext/module/aliasing'
class Range
  #:nodoc:
  def each_with_time_with_zone(&block)
    ensure_iteration_allowed
    each_without_time_with_zone(&block)
  end
  alias_method_chain :each, :time_with_zone

  def step_with_time_with_zone(n = 1, &block)
    ensure_iteration_allowed
    step_without_time_with_zone(n, &block)
  end
  alias_method_chain :step, :time_with_zone

  private

  def ensure_iteration_allowed
    if first.is_a?(Time)
      raise TypeError, "can't iterate from #{first.class}"
    end
  end
end

और इसे एक मॉड्यूल से बदलें, बजाय:

require 'active_support/core_ext/module/aliasing'
module RangeWithTimeWithZoneSupport
  #:nodoc:
  def each(&block)
    ensure_iteration_allowed
    super(&block)
  end

  def step(n = 1, &block)
    ensure_iteration_allowed
    super(n, &block)
  end

  private

  def ensure_iteration_allowed
    if first.is_a?(Time)
      raise TypeError, "can't iterate from #{first.class}"
    end
  end
end

Range.send(:prepend, RangeSupportingTimeWithZone)

यह क्लीनर है, Range#each का नाम नहीं बदला जाता, और ensure_iteration_allowed मंकी-पैच नहीं किया जाता।

पैच नहीं, इनहेरिटेंस का उपयोग करें

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

alias_method_chain सबसे अच्छे मेथड्स में से एक था जिससे मुझे रेल्स में परिचित कराया गया था। लेकिन इसके दिन गिने-चुने हैं। हम इससे आगे निकल चुके हैं। और जब यह चला जाएगा तो मुझे इसकी कमी नहीं खलेगी।

  1. विंडोज विस्टा सपोर्ट समाप्ति के लिए आपको क्या जानने और करने की आवश्यकता है विंडोज विस्टा सपोर्ट समाप्ति के लिए आपको क्या जानने और करने की आवश्यकता है

    क्या आपके पास विंडोज विस्टा चलाने वाला कंप्यूटर है या आप उसका उपयोग करते हैं? हालांकि यह काफी पुराना ऑपरेटिंग सिस्टम बनता जा रहा है, यह अभी भी दैनिक जीवन की मांगों के खिलाफ अच्छा प्रदर्शन कर सकता है। जैसे, ऐसे लोग हैं जो अभी भी काम और/या खेल के लिए विस्टा OS पर भरोसा करते हैं। दुर्भाग्य से, 11 अप्रै

  1. Python और Matplotlib का उपयोग करके लाइन्स के अंत को कैसे एनोटेट करें? Python और Matplotlib का उपयोग करके लाइन्स के अंत को कैसे एनोटेट करें?

    Python और Matplotlib का उपयोग करके लाइन्स के अंत को एनोटेट करने के लिए, हम निम्नलिखित चरण अपना सकते हैं -फिगर का आकार सेट करें और सबप्लॉट्स के बीच और आसपास पैडिंग एडजस्ट करें।पंक्तियों की संख्या प्राप्त करने के लिए rows वेरिएबल इनिशियलाइज़ करें।आयताकार टेबुलर डेटा में Pandas डेटाफ्रेम प्राप्त करें।ड

  1. - Rails में CarrierWave के साथ मास्टर फ़ाइल अपलोड

    Uploading with Rails श्रृंखला का यह एक और लेख है। आज हम CarrierWave से मिलेंगे—Rails के लिए सबसे लोकप्रिय फ़ाइल अपलोड समाधानों में से एक। मुझे CarrierWave पसंद है क्योंकि यह शुरू करना आसान है, इसमें बॉक्स से बाहर कई विशेषताएं हैं, और समुदाय के सदस्यों द्वारा लिखे गए दर्जनों कैसे करें लेख प्रदान करता