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

मेथड_मिसिंग के साथ पूर्वज श्रृंखला तक

अपने कैरी-ऑन सामान को पकड़ें, क्योंकि आज हम पूर्वजों की श्रृंखला तक पूरी यात्रा करेंगे। हम एक विधि कॉल का पालन करेंगे और देखेंगे कि यह कैसे श्रृंखला में ऊपर जाता है और साथ ही यह पता लगाएंगे कि क्या होता है यदि विधि गायब है। और चूँकि हम आग से खेलना पसंद करते हैं, इसलिए हम यहीं नहीं रुकेंगे बल्कि आग से खेलना जारी रखेंगे। 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 क्लास' प्रीपेड मॉड्यूल — उपयोगकर्ताओं के प्रत्यक्ष अभिभावक के रूप में
  • Collection कक्षा
  • Collection क्लास' में मॉड्यूल शामिल हैं —कोई नहीं
  • Object class — किसी भी वर्ग की डिफ़ॉल्ट विरासत
  • Kernel मॉड्यूल — Object . में शामिल है और मुख्य विधियों को धारण करना
  • BasicObject class — रूबी में मूल वर्ग

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

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

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

विधि खोज पथ

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

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

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#each_with_index इस संदेश के लिए विधि कहा जाता है।

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

  • संग्रह each_with_index message का जवाब देता है => नहीं
  • ऐरे each_with_index message का जवाब देता है => नहीं
  • each_with_index message का अनगिनत जवाब => हां

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

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

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

BasicObject#method_missing

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

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 — जो रूबी में किसी भी वर्ग का मूल वर्ग है — इस पद्धति के न्यूनतम संस्करण को परिभाषित करता है। क्लासिक रूबी मैजिक, क्या करना चाहिए?

तो चलिए इस विधि को हमारे 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 . के प्रतिनिधि के रूप में कार्य करता है उदाहरण चर। दरअसल, रूबी मोटे तौर पर ऑब्जेक्ट डेलिगेशन को संभालता है — c.f: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.method_missing . को लागू करने जा रहे हैं प्रत्येक HTML टैग के लिए एक विधि को परिभाषित करने से बचने के लिए विधि।

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

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

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

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

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

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

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

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

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

निष्कर्ष

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

वोइला!


  1. रूबी मानचित्र विधि का उपयोग कैसे करें (उदाहरण के साथ)

    मैप एक रूबी विधि है जिसका उपयोग आप ऐरे, हैश और रेंज के साथ कर सकते हैं। मानचित्र का मुख्य उपयोग डेटा को ट्रांसफ़ॉर्म करना है। उदाहरण के लिए : स्ट्रिंग्स की एक सरणी को देखते हुए, आप प्रत्येक स्ट्रिंग पर जा सकते हैं और प्रत्येक वर्ण को अपरकेस बना सकते हैं। या यदि आपके पास User . की सूची है ऑब्जेक्

  1. रूबी ट्रांसपोज़ विधि के साथ पंक्तियों को कॉलम में बदलें

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

  1. मेटाप्रोग्रामिंग की छिपी लागत

    मेटाप्रोग्रामिंग एक बहुत ही फैंसी शब्द की तरह लगता है, लेकिन क्या यह अच्छा है? यह उपयोगी हो सकता है, लेकिन बहुत से लोग यह नहीं समझते हैं कि मेटाप्रोग्रामिंग का उपयोग करने की कुछ लागतें हैं। ठीक वैसे ही हम एक ही पृष्ठ पर हैं… मेटाप्रोग्रामिंग क्या है बिल्कुल? मैं मेटाप्रोग्रामिंग को किसी भी विधि