आप क्या सोचते हैं जब आप एक मेथड कॉल करते हैं? रूबी कैसे तय करता है कि किस मेथड को कॉल करना है जब उसी नाम का एक और मेथड होता है? क्या आपने कभी सोचा है कि मेथड कहां स्थित है या कहां से आता है?
रूबी सही मेथड को कॉल करने और "नो मेथड एरर" वापस करने का सही समय निर्धारित करने के लिए एक परिभाषित "तरीके" या "पैटर्न" का उपयोग करता है, और हम इस "तरीके" को रूबी मेथड लुकअप पाथ कह सकते हैं। इस ट्यूटोरियल में, हम रूबी के मेथड लुकअप में गोता लगाएंगे। अंत में, आपको इस बात की अच्छी समझ होगी कि रूबी किसी ऑब्जेक्ट के हायरार्की को कैसे पार करता है ताकि यह निर्धारित किया जा सके कि आप किस मेथड का जिक्र कर रहे हैं।
हम जो सीखेंगे उसे पूरी तरह से समझने के लिए, आपको रूबी की बुनियादी समझ होनी चाहिए। जबकि हम मॉड्यूल्स और क्लासेस जैसी चीजों का उल्लेख करेंगे, यह उनमें गहरा गोता नहीं होगा। हम केवल उस गहराई को कवर करेंगे जो इस ट्यूटोरियल के लक्ष्य तक पहुंचने के लिए आवश्यक है: आपको दिखाना कि रूबी कैसे निर्धारित करता है कि आप किसी ऑब्जेक्ट को कौन सा मैसेज (मेथड) पास कर रहे हैं।
अवलोकन
जब आप एक मेथड कॉल करते हैं, जैसे first_person.valid?, रूबी को कुछ चीजें निर्धारित करनी होती हैं:
- मेथड
.valid?कहां परिभाषित है। - क्या कई स्थान हैं जहां
.valid?मेथड परिभाषित है? यदि हां, तो इस संदर्भ में उपयोग करने के लिए सही कौन सा है।
रूबी इसका पता लगाने के लिए जिस प्रक्रिया (या पाथ) का पालन करता है, उसे हम मेथड लुकअप कहते हैं। रूबी को यह ढूंढना होगा कि मेथड कहां बनाया गया था ताकि वह इसे कॉल कर सके। यह सही मेथड को कॉल करना सुनिश्चित करने के लिए निम्न स्थानों में खोज करता है:
- सिंगलटन मेथड्स: रूबी एक ऑब्जेक्ट को अपने स्वयं के मेथड्स को परिभाषित करने का एक तरीका प्रदान करता है; ये मेथड्स केवल उस ऑब्जेक्ट के लिए उपलब्ध होते हैं और ऑब्जेक्ट के इंस्टेंस द्वारा एक्सेस नहीं किए जा सकते।
- मिक्स-इन मॉड्यूल्स में मेथड्स: मॉड्यूल्स को
prepend,include, याextendका उपयोग करके एक क्लास में मिक्स किया जा सकता है। जब ऐसा होता है, तो क्लास को मॉड्यूल्स में परिभाषित मेथड्स तक पहुंच प्राप्त होती है, और रूबी कॉल किए गए मेथड को खोजने के लिए मॉड्यूल्स में जाता है। यह जानना भी महत्वपूर्ण है कि अन्य मॉड्यूल्स को प्रारंभिक मॉड्यूल्स में मिक्स किया जा सकता है, और खोज उनमें भी आगे बढ़ती है। - इंस्टेंस मेथड्स: ये क्लास में परिभाषित मेथड्स हैं और उस क्लास के इंस्टेंस द्वारा एक्सेसिबल हैं।
- पेरेंट क्लास मेथड्स या मॉड्यूल्स: यदि क्लास किसी अन्य क्लास की चाइल्ड होती है, तो रूबी पेरेंट क्लास में खोज करता है। खोज पेरेंट क्लास के सिंगलटन मेथड्स, मिक्स्ड मॉड्यूल्स और उसके पेरेंट क्लास में जाती है।
- Object, Kernel, और BasicObject: ये वे अंतिम स्थान हैं जहां रूबी खोज करता है। ऐसा इसलिए है क्योंकि रूबी में हर ऑब्जेक्ट के पूर्वजों के हिस्से के रूप में ये होते हैं।
क्लासेस और मॉड्यूल्स
मेथड्स को अक्सर ऑब्जेक्ट्स पर कॉल किया जाता है। ये ऑब्जेक्ट्स कुछ क्लासेस द्वारा बनाए जाते हैं, जो रूबी के बिल्ट-इन क्लासेस या डेवलपर द्वारा बनाई गई क्लासेस हो सकती हैं।
class Human
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
हम ऊपर बनाए गए Human क्लास के इंस्टेंस पर hello मेथड को कॉल कर सकते हैं; उदाहरण के लिए,
john = Human.new("John")
john.hello # आउटपुट -> Hello John
hello मेथड एक इंस्टेंस मेथड है; इसलिए हम इसे Human क्लास के इंस्टेंस पर कॉल कर सकते हैं। ऐसे मामले हो सकते हैं जहां हम मेथड को इंस्टेंस पर कॉल नहीं करना चाहते। इन मामलों में, हम मेथड को क्लास पर ही कॉल करना चाहते हैं। इसे प्राप्त करने के लिए, हमें एक क्लास मेथड बनाना होगा। ऊपर वाली क्लास के लिए क्लास मेथड को परिभाषित करना इस तरह दिखेगा:
def self.me
puts "I am a class method"
end
हम इसे Human.me करके कॉल कर सकते हैं। जैसे-जैसे हमारे एप्लिकेशन की जटिलता बढ़ती है (कल्पना करें कि हम यहां एक नया स्टार्टअप बना रहे हैं), एक समय आ सकता है जब हमारी दो या अधिक क्लासेस में कई मेथड हों जो वही काम करते हैं। यदि ऐसा होता है, तो इसका मतलब है कि हमें चीजों को DRY रखना होगा और यह सुनिश्चित करना होगा कि हम खुद को दोहराएं नहीं। मुद्दा यह है कि हम इन क्लासेस में फंक्शनैलिटी कैसे साझा करते हैं।
यदि आपने पहले मॉड्यूल्स का उपयोग नहीं किया है, तो आप इन "साझा" मेथड्स के लिए सख्ती से एक नई क्लास बनाने के लिए ललचा सकते हैं। हालांकि, ऐसा करने के परिणामस्वरूप नकारात्मक परिणाम हो सकते हैं, खासकर जब आपको मल्टीपल इनहेरिटेंस का उपयोग करने की आवश्यकता होती है, जो रूबी सपोर्ट नहीं करता। मॉड्यूल्स इस केस को संभालने का सबसे अच्छा साधन हैं। मॉड्यूल्स क्लासेस के समान हैं, लेकिन उनके कुछ अंतर हैं। सबसे पहले, यहां एक उदाहरण है कि मॉड्यूल कैसा दिखता है:
module Movement
def walk
puts "I can walk!"
end
end
- परिभाषा
moduleकीवर्ड से शुरू होती हैclassके बजाय। - मॉड्यूल्स के इंस्टेंस नहीं हो सकते, इसलिए आप
Movement.newका उपयोग नहीं कर सकते।
मेथड्स
मेथड्स को किसी विशेष ऑब्जेक्ट द्वारा किए जाने वाले एक्शन्स के रूप में देखा जा सकता है। यदि मेरे पास [2, 3, 4] जैसा एक ऐरे है जिसे numberList नामक वेरिएबल को असाइन किया गया है, तो .push मेथड एक एक्शन है जिसे ऐरे द्वारा डालने के लिए किया जा सकता है जो मान यह प्राप्त करता है उसे ऐरे में। यह कोड स्निपेट एक उदाहरण है:
john.walk
यह आपके लिए यह कहना विशिष्ट हो सकता है, "मैं ऑब्जेक्ट के मेथड को कॉल कर रहा हूं", जिसमें john एक ऑब्जेक्ट को संदर्भित करता है जो Human का इंस्टेंस है, और walk मेथड है। हालांकि, यह पूरी तरह से सच नहीं है क्योंकि अनुमानित मेथड ऑब्जेक्ट के क्लास, सुपरक्लास, या मिक्स-इन मॉड्यूल से आता है।
यह जोड़ना महत्वपूर्ण है कि किसी ऑब्जेक्ट पर, यहां तक कि john जैसे ऑब्जेक्ट पर भी मेथड को परिभाषित करना संभव है, क्योंकि रूबी में सब कुछ एक ऑब्जेक्ट है, यहां तक कि ऑब्जेक्ट्स बनाने के लिए उपयोग की जाने वाली क्लास भी।
def john.drip
puts "My drip is eternal"
end
drip मेथड केवल john को असाइन किए गए ऑब्जेक्ट द्वारा एक्सेसिबल हो सकता है। drip एक सिंगलटन मेथड है जो john ऑब्जेक्ट के लिए उपलब्ध होगा। यह जानना महत्वपूर्ण है कि सिंगलटन मेथड्स और क्लास मेथड्स में कोई अंतर नहीं है, जैसा कि आप इस स्टैक ओवरफ्लो उत्तर से देख सकते हैं। जब तक आप ऊपर दिए गए उदाहरण की तरह किसी ऑब्जेक्ट पर परिभाषित मेथड का जिक्र नहीं कर रहे हैं, यह कहना गलत होगा कि मेथड किसी विशेष ऑब्जेक्ट का है। हमारे उदाहरण में, walk मेथड Movement मॉड्यूल का है, जबकि hello मेथड Human क्लास का है। इस समझ के साथ, इसे एक कदम आगे ले जाना आसान होगा, जो यह है कि किसी ऑब्जेक्ट पर कॉल किए गए सटीक मेथड को निर्धारित करने के लिए, रूबी को ऑब्जेक्ट के क्लास या सुपर क्लास या ऑब्जेक्ट के हायरार्की में मिक्स किए गए मॉड्यूल्स की जांच करनी होगी।
मॉड्यूल्स मिक्स करना
रूबी केवल सिंगल इनहेरिटेंस सपोर्ट करता है; एक क्लास केवल एक क्लास से इनहेरिट कर सकती है। इससे चाइल्ड क्लास के लिए दूसरी क्लास के व्यवहार (मेथड्स) को इनहेरिट करना संभव हो जाता है। जब आपके पास ऐसे व्यवहार होते हैं जिन्हें अलग-अलग क्लासेस में साझा करने की आवश्यकता होती है तो क्या होता है? उदाहरण के लिए, Human क्लास के इंस्टेंस के लिए walk मेथड उपलब्ध कराने के लिए, हम Movement मॉड्यूल को Human क्लास में मिक्स इन कर सकते हैं। इसलिए, include का उपयोग करके Human क्लास का पुनर्लेखन इस तरह दिखेगा:
require "movement" # यह मानते हुए कि हमारे पास movement.rb नामक फाइल में मॉड्यूल है
class Human
include Movement
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
अब, हम इंस्टेंस पर walk मेथड को कॉल कर सकते हैं:
john = Human.new("John")
john.walk
Include
जब आप include कीवर्ड का उपयोग करते हैं, जैसे हमने ऊपर किया, तो शामिल मॉड्यूल(एस) के मेथड्स क्लास में इंस्टेंस मेथड(एस) के रूप में जुड़ जाते हैं। ऐसा इसलिए है क्योंकि included मॉड्यूल को Human क्लास के ancestors में जोड़ा जाता है, जैसे कि Movement मॉड्यूल को Human क्लास के पेरेंट के रूप में देखा जा सकता है। जैसा कि आप ऊपर दिखाए गए उदाहरण में देख सकते हैं, हमने Human क्लास के इंस्टेंस पर walk मेथड को कॉल किया है।
Extend
include के अलावा, रूबी हमें extend कीवर्ड प्रदान करता है। यह मॉड्यूल(एस) के मेथड(एस) को क्लास के लिए क्लास मेथड(एस) के रूप में उपलब्ध कराता है, जिन्हें सिंगलटन मेथड्स के रूप में भी जाना जाता है, जैसा कि हमने पहले सीखा था। इसलिए, यदि हमारे पास Feeding नामक एक मॉड्यूल है जो इस तरह दिखता है
module Feeding
def food
"I make my food :)"
end
end
हम extend Feeding जोड़कर और इसे रिक्वायर करके इस व्यवहार को अपने Human क्लास में साझा कर सकते हैं। हालांकि, इसका उपयोग करने के लिए, इंस्टेंस पर food मेथड को कॉल करने के बजाय, हम इसे क्लास पर ही कॉल करेंगे, उसी तरह जैसे हम क्लास मेथड्स को कॉल करते हैं।
Human.food
Prepend
यह include के समान है लेकिन कुछ अंतरों के साथ, जैसा कि इस पोस्ट में कहा गया है;
यह वास्तव में include की तरह काम करता है, सिवाय इसके कि मॉड्यूल को चेन में क्लास और उसके सुपरक्लास के बीच डालने के बजाय, यह इसे चेन के नीचे, यहां तक कि क्लास से पहले भी डाल देगा।
इसका मतलब है कि जब किसी क्लास इंस्टेंस पर मेथड कॉल किया जाता है, तो रूबी क्लास में देखने से पहले मॉड्यूल मेथड्स में देखेगा।
यदि हमारे पास एक मॉड्यूल है जो hello मेथड को परिभाषित करता है जिसे हम prepend का उपयोग करके Human क्लास में मिक्स करते हैं, तो रूबी क्लास में हमारे पास मौजूद मेथड के बजाय मॉड्यूल में मौजूद मेथड को कॉल करेगा।
रूबी के prepend के काम करने के तरीके को ठीक से समझने के लिए, मैं इस लेख को देखने का सुझाव देता हूं।
मेथड लुकअप पाथ
रूबी इंटरप्रेटर मेथड को कॉल करने का प्रयास करते समय पहली जगह सिंगलटन मेथड्स में देखता है। मैंने यह रेप्ल बनाया है, जिसके साथ आप संभावित परिणाम देखने के लिए खेल सकते हैं।
मान लें कि हमारे पास मॉड्यूल्स और क्लासेस का एक समूह है जो निम्न जैसा दिखता है:
module One
def another
puts "From one module"
end
end
module Two
def another
puts "From two module"
end
end
module Three
def another
puts "From three module"
end
end
class Creature
def another
puts "From creature class"
end
end
आइए इन्हें Human क्लास में मिक्स करें।
class Human < Creature
prepend Three
extend Two
include One
def another
puts "Instance method"
end
def self.another
puts "From Human class singleton"
end
end
मॉड्यूल्स को मिक्स करने के अलावा, हमारे पास एक इंस्टेंस और क्लास मेथड है। आप यह भी देख सकते हैं कि Human क्लास Creature क्लास की सबक्लास है।
पहला लुकअप - सिंगलटन मेथड्स
जब हम Human.another चलाते हैं, तो जो प्रिंट होता है वह है From Human class singleton, जो हमारे क्लास मेथड में है। यदि हम क्लास मेथड को कमेंट आउट करते हैं और फिर से चलाते हैं, तो यह कंसोल पर From two module प्रिंट करेगा। यह उस मॉड्यूल से आता है जिसे हमने extend का उपयोग करके मिक्स किया था। यह दिखाता है कि लुकअप सिंगलटन मेथड्स के बीच शुरू होता है। यदि हम extend Two को हटाते (या कमेंट आउट करते) हैं और कमांड को फिर से चलाते हैं, तो यह एक मेथड मिसिंग एरर फेंकेगा। हमें यह त्रुटि मिलती है क्योंकि रूबी another मेथड को सिंगलटन मेथड्स के बीच नहीं ढूंढ सका।
हम आगे बढ़ेंगे और क्लास इंस्टेंस का उपयोग करके एक इंस्टेंस बनाएंगे:
n = Human.new
हम इंस्टेंस के लिए एक सिंगलटन मेथड भी बनाएंगे:
def n.another
puts "From n object"
end
अब, जब हम n.another चलाते हैं, तो कॉल किया जाने वाला वर्जन n ऑब्जेक्ट पर परिभाषित सिंगलटन मेथड होता है। रूबी इस मामले में extend का उपयोग करके मिक्स किए गए मॉड्यूल को नहीं देखेगा क्योंकि हम क्लास के इंस्टेंस पर मेथड कॉल कर रहे हैं। यह जानना महत्वपूर्ण है कि सिंगलटन मेथड्स की प्रासंगिकता extend का उपयोग करके मिक्स किए गए मॉड्यूल्स से जुड़े मेथड्स से अधिक होती है।
दूसरा लुकअप - prepend का उपयोग करके मिक्स किए गए मॉड्यूल्स
यदि हम n ऑब्जेक्ट पर सिंगलटन मेथड को कमेंट आउट करते हैं और कमांड चलाते हैं, तो कॉल किया जाने वाला मेथड का वर्जन वह मॉड्यूल है जिसे हमने prepend का उपयोग करके मिक्स किया था। ऐसा इसलिए है क्योंकि prepend का उपयोग मॉड्यूल को क्लास से पहले ही डाल देता है।
तीसरा लुकअप - क्लास
यदि हम मॉड्यूल Three को कमेंट आउट करते हैं, तो कॉल किया जाने वाला another मेथड का वर्जन क्लास पर परिभाषित इंस्टेंस मेथड होता है।
चौथा लुकअप - include का उपयोग करके मिक्स किए गए मॉड्यूल्स
अगली जगह जहां रूबी मेथड की खोज करता है, वे मॉड्यूल्स हैं जिन्हें include का उपयोग करके मिक्स किया गया है। इसलिए, जब हम इंस्टेंस मेथड को कमेंट आउट करते हैं, तो हमें जो वर्जन मिलता है वह मॉड्यूल One में होता है।
पांचवां लुकअप - पेरेंट क्लास
यदि क्लास का पेरेंट क्लास है, तो रूबी क्लास में खोज करता है। खोज में पेरेंट क्लास में मिक्स किए गए मॉड्यूल्स में जाना शामिल है; यदि हमारे पास पेरेंट क्लास में मिक्स किए गए मॉड्यूल में परिभाषित मेथड होता, तो मेथड कॉल हो जाता।
मेथड खोज का अंत
हम यह जान सकते हैं कि किसी मेथड की खोज कहां समाप्त होती है, उसके ancestors की जांच करके: क्लास पर .ancestors कॉल करना। Human क्लास के लिए ऐसा करने से [Three, Human, One, Creature, Object, Kernel, BasicObject] वापस आएगा। मेथड की खोज BasicObject क्लास पर समाप्त होती है, जो रूबी की रूट क्लास है। हर ऑब्जेक्ट जो किसी क्लास का इंस्टेंस है, BasicObject क्लास से उत्पन्न हुआ है।
डेवलपर-परिभाषित पेरेंट क्लास के बाद मेथड खोज जाने के बाद, यह निम्न तक पहुंचती है:
Objectक्लासKernelमॉड्यूलBasicObjectक्लास
method_missing मेथड
यदि आप कुछ समय से रूबी का उपयोग कर रहे हैं, तो आप शायद NoMethodError का सामना कर चुके हैं, जो तब होता है जब आप किसी ऑब्जेक्ट पर अज्ञात मेथड को कॉल करने का प्रयास करते हैं। यह तब होता है जब रूबी ऑब्जेक्ट के पूर्वजों से गुजर चुका होता है और कॉल किए गए मेथड को नहीं ढूंढ पाता। आपको प्राप्त होने वाला त्रुटि संदेश method_missing मेथड द्वारा संभाला जाता है, जो BasicObject क्लास में परिभाषित है। उस ऑब्जेक्ट के लिए मेथड को ओवरराइड करना संभव है जिस पर आप मेथड कॉल कर रहे हैं, जिसे आप इसे चेक करके सीख सकते हैं।
निष्कर्ष
अब आप वह पाथ जानते हैं जो रूबी किसी ऑब्जेक्ट पर कॉल किए गए मेथड का पता लगाने में लेता है। इस समझ के साथ, आपको अज्ञात मेथड को किसी ऑब्जेक्ट पर कॉल करने के परिणामस्वरूप होने वाली त्रुटियों को आसानी से ठीक करने में सक्षम होना चाहिए।