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

method_missing का उपयोग करके रूबी की पूर्वज श्रृंखला में महारत हासिल करना

अपना कैरी-ऑन लगेज पकड़ें, क्योंकि आज हम पूर्वज श्रृंखला में सबसे ऊपर तक यात्रा करेंगे। हम एक विधि कॉल का अनुसरण करेंगे और देखेंगे कि यह श्रृंखला में कैसे ऊपर जाती है और साथ ही पता लगाएंगे कि क्या होता है जब विधि गायब होती है। और चूंकि हम आग से खेलना पसंद करते हैं, हम वहां नहीं रुकेंगे बल्कि BasicObject#method_missing को ओवरराइड करने पर जारी रखेंगे। यदि आप ध्यान देते हैं, तो हम इसका एक व्यावहारिक उदाहरण में भी उपयोग कर सकते हैं। कोई गारंटी नहीं। चलते हैं!

पूर्वज श्रृंखला

आइए रूबी में पूर्वज श्रृंखला के मौलिक नियमों से शुरू करें:

  • रूबी केवल एकल विरासत का समर्थन करती है
  • यह एक ऑब्जेक्ट को मॉड्यूल्स के एक सेट को शामिल करने की भी अनुमति देती है

रूबी में, पूर्वज श्रृंखला किसी दिए गए क्लास के लिए विरासत में मिले सभी क्लासेस और मॉड्यूल्स के ट्रैवर्सल से बनी होती है।

आइए एक उदाहरण देखें जो दिखाता है कि रूबी में पूर्वज श्रृंखला को कैसे संभाला जाता है।

module Auth end module Session end module Iterable end class Collection prepend Iterable end class Users < Collection prepend Session include Auth end p Users.ancestors

उत्पादन करता है:

[ Session, Users, Auth, # Users Iterable, Collection, # Collection Object, Kernel, BasicObject # Ruby Object Model ]

सबसे पहले, हम किसी दिए गए क्लास की पूर्वज श्रृंखला तक पहुंचने के लिए ancestors क्लास विधि को कॉल करते हैं।

हम देख सकते हैं कि Users.ancestors की कॉल क्लासेस और मॉड्यूल्स की एक सरणी लौटाती है जिनमें क्रम में होते हैं:

  • Users के प्रीपेंडेड मॉड्यूल्स
  • Users क्लास
  • Users क्लास के शामिल मॉड्यूल्स
  • Collection क्लास के प्रीपेंडेड मॉड्यूल्स — Users के डायरेक्ट पैरेंट के रूप में
  • Collection क्लास
  • Collection क्लास के शामिल मॉड्यूल्स — कोई नहीं
  • Object क्लास — किसी भी क्लास की डिफ़ॉल्ट विरासत
  • Kernel मॉड्यूल — Object में शामिल और कोर विधियों को धारण करने वाला
  • BasicObject क्लास — रूबी में रूट क्लास

तो, किसी दिए गए ट्रैवर्स्ड क्लास या मॉड्यूल के लिए उपस्थिति का क्रम हमेशा निम्नानुसार होता है:

  • प्रीपेंडेड मॉड्यूल्स
  • क्लास या मॉड्यूल
  • इसके शामिल मॉड्यूल्स

पूर्वज श्रृंखला को मुख्य रूप से रूबी द्वारा तब ट्रैवर्स किया जाता है जब किसी ऑब्जेक्ट या क्लास पर कोई विधि लागू की जाती है।

विधि लुकअप पथ

जब एक संदेश भेजा जाता है, तो रूबी संदेश रिसीवर की पूर्वज श्रृंखला को ट्रैवर्स करती है और जांचती है कि क्या उनमें से कोई दिए गए संदेश का जवाब देता है।

यदि पूर्वज श्रृंखला का कोई दिया गया क्लास या मॉड्यूल संदेश का जवाब देता है, तो इस संदेश से जुड़ी विधि निष्पादित होती है और पूर्वज श्रृंखला ट्रैवर्सल रुक जाती है।

class Collection < Array end Collection.ancestors # => [Collection, Array, Enumerable, Object, Kernel, BasicObject] collection = Collection.new([:a, :b, :c]) collection.each_with_index # => :a

यहां, collection.each_with_index संदेश Enumerable मॉड्यूल द्वारा प्राप्त किया जाता है। फिर इस संदेश के लिए Enumerable#each_with_index विधि को कॉल किया जाता है।

यहां, जब collection.each_with_index को कॉल किया जाता है, तो रूबी जांचती है कि:

  • Collection each_with_index message का जवाब देता है => नहीं
  • Array each_with_index message का जवाब देता है => नहीं
  • Enumerable each_with_index message का जवाब देता है => हाँ

तो, यहां से, रूबी पूर्वज श्रृंखला ट्रैवर्सल को रोक देती है और इस संदेश से जुड़ी विधि को कॉल करती है। हमारे मामले में, Enumerable#each_with_index विधि।

रूबी में, इस तंत्र को विधि लुकअप पथ कहा जाता है।

अब, क्या होता है यदि दिए गए रिसीवर की पूर्वज श्रृंखला को बनाने वाले कोई भी क्लास और मॉड्यूल संदेश का जवाब नहीं देते?

BasicObject#method_missing

अब अच्छा बनना बंद! आइए चीजों को तोड़ें, डेवलपर स्टाइल में: अपवाद फेंककर। हम एक Collection क्लास लागू करेंगे और इसके एक इंस्टेंस पर एक अज्ञात विधि कॉल करेंगे।

class Collection end c = Collection.new c.search('item1') # => NoMethodError: undefined method `search` for #<Collection:0x123456890>

यहां, Collection क्लास search विधि को लागू नहीं करती। तो एक NoMethodError उठाया जाता है। लेकिन यह त्रुटि उठाना कहां से आता है?

त्रुटि BasicObject#method_missing विधि में उठाई जाती है। यह विधि तब कॉल की जाती है जब विधि लुकअप पथ दिए गए संदेश से मेल खाने वाली किसी भी विधि को खोजने में विफल रहता है।

ठीक है... लेकिन यह विधि केवल NoMethodError उठाती है। इसलिए इसे अपने Collection क्लास के संदर्भ में ओवरराइड करने में सक्षम होना बहुत अच्छा होगा।

BasicObject#method_missing विधि को ओवरराइड करना

अंदाजा लगाओ? method_missing को ओवरराइड करना पूरी तरह से ठीक है क्योंकि यह विधि विधि लुकअप पथ के तंत्र के अधीन भी है। एक सामान्य विधि के साथ एकमात्र अंतर यह है कि हम सुनिश्चित हैं कि यह विधि विधि लुकअप पथ द्वारा कम से कम एक बार पाई जाएगी।

वास्तव में, BasicObject class — जो रूबी में किसी भी क्लास की रूट क्लास है — इस विधि का एक न्यूनतम संस्करण परिभाषित करता है। क्लासिक रूबी मैजिक, न'est-ce pas?

तो आइए इस विधि को अपने Collection class में ओवरराइड करें:

class Collection def initialize @collection = {} end def method_missing(method_id, *args) if method_id[-1] == '=' key = method_id[0..-2] @collection[key.to_sym] = args.first else @collection[method_id] end end end collection = Collection.new collection.obj1 = 'value1' collection.obj2 = 'value2' collection.obj1 # => 'value1' collection.obj2 # => 'value2'

यहां, Collection#method_missing @collection इंस्टेंस वेरिएबल के लिए एक डेलीगेटर के रूप में कार्य करता है। वास्तव में, यह वही तरीका है जिससे रूबी मोटे तौर पर ऑब्जेक्ट डेलीगेशन को संभालती है — cf: delegate लाइब्रेरी।

यदि गायब विधि एक सेटर विधि है (collection.obj1 = 'value1'), तो विधि नाम (:obj1) को कुंजी के रूप में और आर्गुमेंट ('value1') को @collection हैश एंट्री के मान के रूप में उपयोग किया जाता है (@collection[:obj1] = 'value1')।

एक HTML टैग जेनरेटर

अब जब हम जानते हैं कि method_missing विधि पर्दे के पीछे कैसे काम करती है, आइए एक पुनरुत्पादन योग्य उपयोग केस लागू करें।

यहां, लक्ष्य निम्नलिखित DSL को परिभाषित करना है:

HTML.p 'hello world' # => <p>hello world</p> HTML.div 'hello world' # => <div>hello world</div> HTML.h1 'hello world' # => <h1>hello world</h1> HTML.h2 'hello world' # => <h2>hello world</h2> HTML.span 'hello world' # => <span>hello world</span> HTML.p "hello #{HTML.b 'world'}" # => <p>hello <b>world</b></p>

ऐसा करने के लिए, हम प्रत्येक HTML टैग के लिए एक विधि को परिभाषित करने से बचने के लिए HTML.method_missing विधि को लागू करने जा रहे हैं।

सबसे पहले, हम एक HTML मॉड्यूल परिभाषित करते हैं। फिर हम इस मॉड्यूल में एक method_missing क्लास विधि परिभाषित करते हैं:

module HTML def HTML.method_missing(method_id, *args, &block) "<#{method_id}>#{args.first}</#{method_id}>" end end

हमारी विधि केवल गायब method_id का उपयोग करके एक HTML टैग बनाएगी — उदाहरण के लिए HTML.div की कॉल के लिए :div।

ध्यान दें कि क्लास विधियां भी विधि लुकअप पथ के अधीन हैं।

हम अपने HTML टैग जेनरेटर को निम्न द्वारा बढ़ा सकते हैं:

  • नेस्टेड टैग्स को संभालने के लिए ब्लॉक आर्गुमेंट का उपयोग करना
  • सिंगल टैग्स को संभालना — उदाहरण के लिए <br/>

लेकिन ध्यान दें कि कोड की कुछ पंक्तियों के साथ, हम बड़ी मात्रा में HTML टैग्स जेनरेट करने में सक्षम हैं।

तो, संक्षेप में:

method_missing उन DSLs को बनाने के लिए एक अच्छा प्रवेश बिंदु है जहां अधिकांश कमांड पहचाने गए पैटर्न के एक सेट को साझा करेंगे।

निष्कर्ष

हम रूबी में पूर्वज श्रृंखला में सबसे ऊपर तक गए और BasicObject#method_missing में गोता लगाया। BasicObject#method_missing रूबी हुक विधियों का हिस्सा है। इसका उपयोग ऑब्जेक्ट्स के साथ उनके जीवनचक्र में कुछ सटीक क्षणों में बातचीत करने के लिए किया जाता है। अन्य रूबी हुक विधियों की तरह, इस हुक विधि का सावधानी से उपयोग किया जाना चाहिए। और सावधानी से, हमारा मतलब है कि इसे कभी भी रूबी ऑब्जेक्ट मॉडल के व्यवहार को संशोधित नहीं करना चाहिए — सिवाय जब आप इसके साथ खेल रहे हों या इस पर एक ब्लॉग पोस्ट लिख रहे हों ;-)

Voilà!

  1. Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड

    Map एक Ruby मेथड है जिसका उपयोग आप Arrays, Hashes और Ranges के साथ कर सकते हैं। map का मुख्य उपयोग डेटा को ट्रांसफॉर्म करना है। उदाहरण के लिए: स्ट्रिंग्स की एक सरणी दिए जाने पर, आप हर स्ट्रिंग पर जा सकते हैं और हर कैरेक्टर को UPPERCASE बना सकते हैं। या यदि आपके पास User ऑब्जेक्ट्स की एक सूची है... आ

  1. रूबी में Transpose मेथड का उपयोग करके आसानी से पंक्तियों को स्तंभों में बदलें रूबी में Transpose मेथड का उपयोग करके आसानी से पंक्तियों को स्तंभों में बदलें

    आज आप सीखेंगे कि रूबी transpose मेथड का उपयोग करके ग्रिड्स से कैसे निपटें। कल्पना करें कि आपके पास एक परफेक्ट ग्रिड है, मान लीजिए एक 3×3 वर्ग, बहुआयामी सरणी के रूप में। और आप पंक्तियों को लेना और उन्हें स्तंभों में बदलना चाहते हैं। आप ऐसा क्यों करना चाहेंगे? एक उपयोग क्लासिक गेम के लिए है: टिक-टैक-ट

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

    मेटाप्रोग्रामिंग बहुत फैंसी शब्द लगता है, लेकिन क्या यह अच्छा है? यह उपयोगी हो सकता है, लेकिन बहुत से लोग यह नहीं समझते कि मेटाप्रोग्रामिंग का उपयोग करने की कुछ लागतें हैं। बस ताकि हम एक ही पेज पर हों... मेटाप्रोग्रामिंग वास्तव में क्या है? मैं मेटाप्रोग्रामिंग को किसी भी मेथड का उपयोग करने के रूप म