आपको क्या लगता है कि जब आप किसी विधि को कॉल करते हैं तो क्या होता है? रूबी कैसे तय करती है कि उसी नाम से दूसरी विधि होने पर किस विधि को कॉल करना है? क्या आपने कभी सोचा है कि विधि कहाँ से रखी गई है या कहाँ से प्राप्त की गई है?
रूबी कॉल करने के लिए सही विधि और "कोई विधि त्रुटि नहीं" वापस करने के लिए सही समय निर्धारित करने के लिए एक परिभाषित "रास्ता" या "पैटर्न" नियोजित करता है, और हम इसे "रास्ता" रूबी विधि लुकअप पथ .इस ट्यूटोरियल में, हम रूबी के मेथड लुकअप के बारे में जानेंगे। अंत में, आपको इस बात की अच्छी समझ होगी कि रूबी किसी वस्तु के पदानुक्रम से कैसे गुजरती है, यह निर्धारित करने के लिए कि आप किस विधि का उल्लेख कर रहे हैं।
हम जो सीखेंगे उसे पूरी तरह से समझने के लिए, आपको रूबी की बुनियादी समझ होनी चाहिए। जबकि हम मॉड्यूल और कक्षाओं जैसी चीजों का उल्लेख करेंगे, यह उनके द्वारा किए जाने वाले कार्यों में गहरा गोता नहीं होगा। हम केवल इस ट्यूटोरियल के लक्ष्य तक पहुँचने के लिए आवश्यक गहराई को कवर करेंगे:आपको दिखाते हैं कि रूबी उस संदेश (विधि) को कैसे निर्धारित करती है जिसे आप किसी ऑब्जेक्ट को भेज रहे हैं।
अवलोकन
जब आप किसी विधि को कॉल करते हैं, जैसे first_person.valid?
, रूबी को कुछ चीज़ें तय करनी होती हैं:
- विधि कहां
.valid?
परिभाषित किया गया है। - क्या ऐसे कई स्थान हैं जहां
.valid?
विधि परिभाषित है? यदि हां, तो इस संदर्भ में उपयोग करने के लिए कौन सा सही है।
प्रक्रिया (या पथ) रूबी यह पता लगाने में अनुसरण करती है जिसे हम विधि खोज . कहते हैं . रूबी को यह पता लगाना है कि विधि कहाँ बनाई गई थी ताकि वह इसे कॉल कर सके। यह सुनिश्चित करने के लिए कि यह सही विधि कहता है, इसे निम्नलिखित स्थानों में खोजना होगा:
- सिंगलटन विधियाँ:रूबी किसी वस्तु को अपनी विधियों को परिभाषित करने का एक तरीका प्रदान करती है; ये विधियां केवल उस ऑब्जेक्ट के लिए उपलब्ध हैं और ऑब्जेक्ट के इंस्टेंस द्वारा एक्सेस नहीं की जा सकती हैं।
- मिश्रित मॉड्यूल में विधियां:मॉड्यूल को
prepend
का उपयोग करके एक वर्ग में मिश्रित किया जा सकता है ,include
, याextend
. जब ऐसा होता है, तो कक्षा के पास मॉड्यूल में परिभाषित विधियों तक पहुंच होती है, और रूबी मॉड्यूल में उस विधि की खोज करने के लिए जाती है जिसे बुलाया गया है। यह जानना भी महत्वपूर्ण है कि अन्य मॉड्यूल को प्रारंभिक मॉड्यूल में मिलाया जा सकता है, और खोज भी इनमें आगे बढ़ती है। - इंस्टेंस मेथड्स:ये क्लास में परिभाषित मेथड्स हैं और उस क्लास के इंस्टेंसेस द्वारा एक्सेस किए जा सकते हैं।
- अभिभावक वर्ग के तरीके या मॉड्यूल:यदि वर्ग किसी अन्य वर्ग का बच्चा होता है, रूबी मूल वर्ग में खोज करता है। खोज मूल वर्ग सिंगलटन विधियों, मिश्रित मॉड्यूल और उसके मूल वर्ग में जाती है।
- ऑब्जेक्ट, कर्नेल और बेसिकऑब्जेक्ट:ये अंतिम स्थान हैं जहां रूबी खोजता है। ऐसा इसलिए है क्योंकि रूबी में हर वस्तु में ये उनके पूर्वजों के हिस्से के रूप में होते हैं।
कक्षाएं और मॉड्यूल
विधियों को अक्सर वस्तुओं पर बुलाया जाता है। ये ऑब्जेक्ट कुछ वर्गों द्वारा बनाए गए हैं, जो रूबी की अंतर्निहित कक्षाएं या डेवलपर द्वारा बनाई गई कक्षाएं हो सकती हैं।
class Human
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
फिर हम hello
. को कॉल कर सकते हैं विधि जिसे हमने ऊपर Human
. के उदाहरणों पर बनाया है कक्षा; उदाहरण के लिए,
john = Human.new("John")
john.hello # Output -> Hello John
hello
विधि एक उदाहरण विधि है; यही कारण है कि हम इसे Human
. के उदाहरणों पर कह सकते हैं कक्षा। ऐसे मामले हो सकते हैं जहां हम नहीं चाहते कि विधि को उदाहरणों पर बुलाया जाए। इन मामलों में, हम कक्षा पर ही विधि को कॉल करना चाहते हैं। इसे प्राप्त करने के लिए, हमें एक वर्ग विधि बनानी होगी। ऊपर दी गई कक्षा के लिए क्लास मेथड को परिभाषित करना इस तरह दिखेगा:
def self.me
puts "I am a class method"
end
इसके बाद हम इसे Human.me
. करके कॉल कर सकते हैं . जैसे-जैसे हमारे आवेदन की जटिलता बढ़ती है (कल्पना कीजिए कि हम यहां एक नया स्टार्ट-अप बना रहे हैं), ऐसा समय आ सकता है जब हमारी दो या अधिक कक्षाओं में एक ही काम करने वाली कई विधियां हों। अगर ऐसा होता है, तो इसका मतलब है कि हमें चीजों को सूखा रखना होगा और यह सुनिश्चित करना होगा कि हम खुद को न दोहराएं। इस मुद्दे में यह शामिल है कि हम इन वर्गों में कार्यक्षमता कैसे साझा करते हैं।
यदि आपने पहले मॉड्यूल का उपयोग नहीं किया है, तो आप इन "साझा" विधियों के लिए सख्ती से एक नया वर्ग बनाने का लुत्फ उठा सकते हैं। हालांकि, ऐसा करने से नकारात्मक परिणाम हो सकते हैं, खासकर जब आपको एकाधिक विरासत का उपयोग करने की आवश्यकता होती है, ऐसा कुछ जो रूबी का समर्थन नहीं करता है। मॉड्यूल इस मामले को संभालने का सबसे अच्छा साधन हैं। मॉड्यूल कक्षाओं के समान हैं, लेकिन उनमें कुछ अंतर हैं। सबसे पहले, यहां एक उदाहरण दिया गया है कि मॉड्यूल कैसा दिखता है:
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
. से संबंधित है कक्षा। इस समझ के साथ, इसे एक कदम आगे ले जाना आसान हो जाएगा, जो यह है कि किसी ऑब्जेक्ट पर कॉल की जा रही सटीक विधि को निर्धारित करने के लिए, रूबी को ऑब्जेक्ट की क्लास या सुपर क्लास या मॉड्यूल की जांच करनी होगी जो मिश्रित हो गए हैं वस्तु के पदानुक्रम में।
मिश्रण मॉड्यूल
रूबी केवल एकल वंशानुक्रम का समर्थन करती है; एक वर्ग केवल एक वर्ग से विरासत में मिल सकता है। यह बाल वर्ग के लिए किसी अन्य वर्ग के व्यवहार (विधियों) को विरासत में प्राप्त करना संभव बनाता है। क्या होता है जब आपके पास ऐसे व्यवहार होते हैं जिन्हें विभिन्न वर्गों में साझा करने की आवश्यकता होती है? उदाहरण के लिए, walk
. बनाने के लिए Human
. के उदाहरणों के लिए उपलब्ध विधि कक्षा, हम मिश्रित . कर सकते हैं Movement
Human
. में मॉड्यूल कक्षा। तो, Human
. का पुनर्लेखन include
. का उपयोग कर वर्ग इस तरह दिखेगा:
require "movement" # Assuming we have the module in a file called 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
शामिल करें
जब आप शामिल करें . का उपयोग करते हैं कीवर्ड, जैसा कि हमने ऊपर किया था, सम्मिलित मॉड्यूल के तरीके वर्ग में उदाहरण विधि के रूप में जुड़ जाते हैं। ऐसा इसलिए है क्योंकि शामिल मॉड्यूल को पूर्वजों . में जोड़ा गया है Human
. का वर्ग, जैसे कि Movement
मॉड्यूल को Human
. के अभिभावक के रूप में देखा जा सकता है कक्षा। जैसा कि आप ऊपर दिखाए गए उदाहरण में देख सकते हैं, हमने walk
. कहा है Human
. के उदाहरण पर विधि कक्षा।
विस्तार करें
शामिल करें . के अलावा , रूबी हमें विस्तार . प्रदान करती है खोजशब्द। यह मॉड्यूल की विधि (ओं) को कक्षा के लिए वर्ग विधि के रूप में उपलब्ध कराता है, जिसे सिंगलटन विधियों के रूप में भी जाना जाता है, जैसा कि हमने पहले सीखा था। इसलिए, यदि हमारे पास Feeding
. नामक एक मॉड्यूल है ऐसा दिखता है
module Feeding
def food
"I make my food :)"
end
end
फिर हम इस व्यवहार को अपने Human
. में साझा कर सकते हैं क्लास की आवश्यकता के अनुसार और extend Feeding
. जोड़कर . हालांकि, इसका इस्तेमाल करने के लिए food
. को कॉल करने के बजाय क्लास के इंस्टेंस पर मेथड, हम इसे क्लास में ही कॉल करेंगे, वैसे ही हम क्लास मेथड्स को कहते हैं।
Human.food
तैयार करें
यह शामिल करें . के समान है लेकिन कुछ अंतरों के साथ, जैसा कि इस पोस्ट में बताया गया है;
<ब्लॉकक्वॉट>यह वास्तव में शामिल की तरह काम करता है, सिवाय इसके कि श्रृंखला में वर्ग और उसके सुपरक्लास के बीच मॉड्यूल डालने के बजाय, यह इसे श्रृंखला के निचले भाग में, कक्षा से पहले ही सम्मिलित कर देगा।
इसका मतलब यह है कि क्लास इंस्टेंस पर एक विधि को कॉल करते समय, रूबी कक्षा में देखने से पहले मॉड्यूल विधियों को देखेगा।
अगर हमारे पास एक मॉड्यूल है जो hello
. को परिभाषित करता है विधि जिसे हम तब Human
. में मिलाते हैं prepend
. का उपयोग करके कक्षा , रूबी हमारे पास कक्षा में मौजूद विधि के बजाय मॉड्यूल में हमारे पास मौजूद विधि को कॉल करेगी।
रूबी के 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
और फिर से कमांड चलाएँ, यह एक विधि अनुपलब्ध त्रुटि throw को फेंक देगा . हमें यह त्रुटि इसलिए मिलती है क्योंकि रूबी को another
नहीं मिला सिंगलटन विधियों के बीच विधि।
हम आगे बढ़ेंगे और एक इंस्टेंस बनाकर क्लास इंस्टेंस का उपयोग करेंगे:
n = Human.new
उदाहरण के लिए हम सिंगलटन विधि भी बनाएंगे:
def n.another
puts "From n object"
end
अब, जब हम n.another
run चलाते हैं , जिस संस्करण को कॉल किया जाता है वह n
. पर परिभाषित सिंगलटन विधि है वस्तु। रूबी extend
. का उपयोग करके मिश्रित मॉड्यूल को कॉल नहीं करेगी इसका कारण इस मामले में क्योंकि हम कक्षा के उदाहरण पर विधि को बुला रहे हैं। यह जानना महत्वपूर्ण है कि सिंगलटन विधियों में extend
का उपयोग करने में मिश्रित मॉड्यूल शामिल विधियों की तुलना में अधिक प्रासंगिकता है। ।
दूसरा लुकअप - preprend
का उपयोग करने में मिश्रित मॉड्यूल
अगर हम n
. पर सिंगलटन विधि पर टिप्पणी करते हैं ऑब्जेक्ट करें और कमांड चलाएं, विधि का संस्करण जिसे कॉल किया जाता है वह मॉड्यूल है जिसे हमने prepend
का उपयोग करके मिश्रित किया है . ऐसा इसलिए है क्योंकि prepend
. का उपयोग मॉड्यूल को कक्षा से पहले ही सम्मिलित करता है।
थर्ड लुकअप - द क्लास
यदि हम मॉड्यूल पर टिप्पणी करते हैं Three
, another
. का संस्करण कॉल की जाने वाली विधि कक्षा में परिभाषित इंस्टेंस विधि है।
चौथा लुकअप - उपयोग करने में मिश्रित मॉड्यूल include
रूबी विधि की खोज करने वाला अगला स्थान मॉड्यूल में है जिसे include
. का उपयोग करके मिश्रित किया गया है . इसलिए, जब हम इंस्टेंस विधि पर टिप्पणी करते हैं, तो हमें जो संस्करण मिलता है, वह मॉड्यूल One
. में होता है ।
पांचवां लुकअप - अभिभावक वर्ग
यदि कक्षा में मूल वर्ग है, तो रूबी कक्षा में खोज करती है। खोज में मूल वर्ग में मिश्रित मॉड्यूल में जाना शामिल है; यदि हमारे पास Creature
. में मिश्रित मॉड्यूल में परिभाषित विधि होती क्लास, मेथड को कॉल किया जाएगा।
विधि खोज का अंत
हम यह जान सकते हैं कि किसी विधि की खोज उसके पूर्वजों की जाँच करके कहाँ समाप्त होती है:.ancestors
. को कॉल करना कक्षा पर। Human
. के लिए ऐसा करना वर्ग वापस आ जाएगा [Three, Human, One, Creature, Object, Kernel, BasicObject]
. किसी विधि की खोज BasicObject
. पर समाप्त होती है क्लास, जो रूबी का रूट क्लास है। प्रत्येक वस्तु जो किसी वर्ग का एक उदाहरण है BasicObject
. से उत्पन्न हुई है कक्षा।
विधि खोज के बाद डेवलपर द्वारा परिभाषित मूल वर्ग से आगे निकल जाता है, यह निम्न तक पहुंच जाता है:
Object
कक्षाKernel
मॉड्यूल- द
BasicObject
कक्षा
method_missing
विधि
यदि आप कुछ समय से रूबी का उपयोग कर रहे हैं, तो संभवतः आप NoMethodError
. पर आ गए हैं , जो तब होता है जब आप किसी वस्तु पर किसी अज्ञात विधि का प्रयास करते हैं। ऐसा तब होता है जब रूबी वस्तु के पूर्वजों के माध्यम से चली जाती है और बुलाए गए विधि को नहीं ढूंढ पाती है। आपको प्राप्त होने वाला त्रुटि संदेश method_missing
. द्वारा नियंत्रित किया जाता है विधि, BasicObject
. में परिभाषित कक्षा। जिस ऑब्जेक्ट पर आप कॉल कर रहे हैं, उसके लिए विधि को ओवरराइड करना संभव है, जिसके बारे में आप इसकी जाँच करके जान सकते हैं।
निष्कर्ष
अब आप जानते हैं कि रूबी किसी वस्तु पर बुलाए गए तरीके का पता लगाने में क्या रास्ता अपनाती है। इस समझ के साथ, आप किसी ऑब्जेक्ट पर किसी अज्ञात विधि को कॉल करने के परिणामस्वरूप उत्पन्न होने वाली त्रुटियों को आसानी से ठीक करने में सक्षम होना चाहिए।