यदि आपने पहले Ruby के एक्सेप्शन के साथ काम किया है, तो आप जानते हैं कि आप निर्दिष्ट कर सकते हैं कि कौन से एक्सेप्शन रेस्क्यू किए जाते हैं और कौन से नहीं:
begin raise ArgumentError rescue ArgumentError # `ArgumentError` को रेस्क्यू करता है end
...और आप शायद यह भी जानते हैं कि जब आप एक "पैरेंट" को रेस्क्यू करते हैं तो आप उसके सभी "चिल्ड्रन" को भी रेस्क्यू करते हैं।
begin raise ArgumentError rescue StandardError # `ArgumentError` को रेस्क्यू करता है, क्योंकि यह # `StandardError` से इनहेरिट करता है end
जब मैं "पैरेंट" और "चाइल्ड" कहता हूं तो मैं केवल क्लास इनहेरिटेंस का जिक्र कर रहा हूं। Ruby सोर्स कोड में कहीं गहरे में इसके समतुल्य कुछ है:
class ArgumentError < StandardError ... end
एक दिलचस्प ट्रिक
यहां मेरा सवाल है: Ruby कैसे जानता है कि कोई दिया गया एक्सेप्शन आपके द्वारा निर्दिष्ट क्लास से इनहेरिट करता है?
सबसे स्पष्ट दृष्टिकोण is_a? या kind_of? मेथड का उपयोग करना होगा। हम कल्पना कर सकते हैं कि यह ऐसा दिखता है:
if the_exception.is_a?(StandardError) # रेस्क्यू करें end
लेकिन ऐसा नहीं होता। इसके बजाय, Ruby अधिक दिलचस्प === ऑपरेटर का उपयोग करता है।
if StandardError === the_exception # रेस्क्यू करें end
यदि आपने कभी a === b का उपयोग नहीं किया है, तो यह आमतौर पर सवाल का जवाब देता है "क्या a स्वाभाविक रूप से b द्वारा परिभाषित समूह से संबंधित है"? यहां कुछ उदाहरण हैं:
(1..10) === 5 # true
('a'..'f') === "z" # false
String === "hello" # true
String === 1 # false
/[0-9]{3}/ === "hello123" # true
/[0-9]{3}/ === "hello" # false
क्योंकि === सिर्फ == की तरह एक सामान्य Ruby मेथड है, हम इसे स्वयं परिभाषित कर सकते हैं:
class RedThings
def self.===(thing)
thing.color == :red
end
end
तो, हम क्या जानते हैं? हम जानते हैं कि rescue यह निर्धारित करने के लिए === का उपयोग करता है कि कौन से एक्सेप्शन रेस्क्यू किए जाते हैं। और हम जानते हैं कि हम अपना खुद का === मेथड परिभाषित कर सकते हैं। इसका मतलब है कि हम एक क्लास बना सकते हैं जो ऑन-द-फ्लाई तय करती है कि कौन से एक्सेप्शन रेस्क्यू किए जाते हैं:
class SevereMatcher
def self.===(exception)
exception.message =~ /severe/
end
end
begin
raise RuntimeError, "Something severe happened"
rescue SevereMatcher
# मैसेज में "severe" शब्द वाले सभी एक्सेप्शन को रेस्क्यू करता है,
# क्लास की परवाह किए बिना।
end
एक बार जब आप इस ट्रिक को जान लेते हैं, तो केवल आपकी कल्पना की सीमा है।
निष्कर्ष
मैं मानूंगा: आपको कभी भी डायनामिक एक्सेप्शन मैचर बनाने की आवश्यकता नहीं हो सकती। लेकिन यह एक दिलचस्प उदाहरण है कि कैसे === का उपयोग kind_of? के बजाय जैसे प्रतीत होने वाले तुच्छ कार्यान्वयन विवरण Ruby को अधिक लचीला और दिलचस्प बनाता है।