जब आप रूबी में बचाव खंड का उपयोग करते हैं, तो आप निर्दिष्ट कर सकते हैं कि आप किस प्रकार के अपवादों को बचाना चाहते हैं। आपको बस इतना करना है कि अपवाद वर्गों की एक सूची प्रदान करें जैसे:
begin
raise RuntimeError
rescue RuntimeError, NoMethodError
puts "rescued!"
end
लेकिन क्या होगा यदि आप नहीं जानते कि कोड लिखते समय अपवाद वर्ग क्या होगा? सबसे स्पष्ट उत्तर सभी अपवादों को बचाना है, किसी प्रकार का परीक्षण करना है और फिर उन अपवादों को फिर से उठाना है जो पास नहीं होते हैं। कुछ इस तरह:
begin
raise "FUBAR! The ship's going down!"
rescue => e
raise unless e.message =~ /^FUBAR/
... do something ...
end
लेकिन यह बहुत उबाऊ है! इसके अलावा, यह एक बहुत ही शुष्क दृष्टिकोण नहीं है। यह बहुत अधिक दिलचस्प होगा यदि हम किसी भी तरह बचाव खंड को केवल हमारी स्थितियों से मेल खाने वाले बचाव अपवादों को बता सकें। और चूंकि यह रूबी है, हम इसे कर सकते हैं!
बचाव अपवादों से कैसे मेल खाता है
जब बचाव ब्लॉक के अंदर कोई अपवाद होता है, तो रूबी दुभाषिया आपके द्वारा प्रदान की गई अपवाद कक्षाओं की सूची के विरुद्ध अपवाद वर्ग की जांच करता है। यदि कोई मिलान होता है, तो अपवाद बच जाता है।
मिलान कुछ इस तरह दिखता है:
exception_classes_to_rescue.any? do |c|
c === raised_exception.class
end
रूबी में हर दूसरे ऑपरेटर की तरह, ===
बस एक तरीका है। इस मामले में यह c
. की एक विधि है . तो अगर हम अपने ===
. को परिभाषित करते हैं तो हम क्या कर सकते हैं? विधि?
नीचे दिए गए उदाहरण में मैं Anything
. नाम की एक क्लास बना रहा हूं जहां Anything === x
x के किसी भी मान के लिए सत्य लौटाता है। अगर मैं इस वर्ग को बचाव के तर्क के रूप में देता हूं, तो इससे सभी अपवादों को बचाया जा सकता है।
class Anything
def self.===(exception)
true
end
end
begin
raise EOFError
rescue Anything
puts "It rescues ANYTHING!"
end
हालांकि सभी अपवादों को बचाने के कई बेहतर तरीके हैं, यह कोड दिलचस्प है क्योंकि यह हमें दो चीजें दिखाता है:
-
आप बचाव खंड वर्ग दे सकते हैं जो
Exception
. से इनहेरिट नहीं करते हैं , जब तक वे===
. लागू करते हैं -
अगर आप
===
. को नियंत्रित करते हैं , आप नियंत्रित कर सकते हैं कि कौन से अपवाद बचाए गए हैं।
संदेश के आधार पर अपवादों को बचाना
यह जानना कि हम अभी क्या जानते हैं, कोड लिखना आसान है जो अपवादों को तभी बचाता है जब अपवाद का संदेश किसी पैटर्न से मेल खाता हो।
class AllFoobarErrors
def self.===(exception)
# rescue all exceptions with messages starting with FOOBAR
exception.message =~ /^FOOBAR/
end
end
begin
raise EOFError, "FOOBAR: there was an eof!"
rescue AllFoobarErrors
puts "rescued!"
end
कस्टम विशेषताओं के आधार पर अपवादों को बचाना
चूंकि आपके पास अपवाद ऑब्जेक्ट तक पहुंच है, इसलिए आपका मैचर उस ऑब्जेक्ट के अंदर मौजूद किसी भी डेटा का उपयोग कर सकता है।
एक पल के लिए कल्पना करें कि आपके पास एक अपवाद है जिसमें "गंभीरता" नामक एक कस्टम विशेषता है। आप अपवाद की सभी "कम गंभीरता" की घटनाओं को निगलना चाहते हैं, लेकिन किसी भी "उच्च गंभीरता" की घटनाओं को पारित करने दें। आप इसे इस तरह लागू कर सकते हैं:
class Infraction < StandardError
attr_reader :severity
def initialize(severity)
@severity = severity
end
end
class LowSeverityInfractions
def self.===(exception)
exception.is_a?(Infraction) && exception.severity == :low
end
end
begin
raise Infraction.new(:low)
rescue LowSeverityInfractions
puts "rescued!"
end
इसे गतिशील बनाना
यह सब बहुत अच्छा है, लेकिन इसमें बहुत सारे बॉयलरप्लेट कोड शामिल हैं। प्रत्येक मिलानकर्ता के लिए अलग-अलग वर्गों को मैन्युअल रूप से परिभाषित करना अत्यधिक लगता है। सौभाग्य से हम थोड़े से मेटाप्रोग्रामिंग का उपयोग करके इसे काफी कम कर सकते हैं।
नीचे दिए गए उदाहरण में, हम एक ऐसी विधि को परिभाषित कर रहे हैं जो हमारे लिए मैचर क्लास उत्पन्न करती है। आप एक ब्लॉक के माध्यम से मिलान तर्क प्रदान करते हैं, और मिलान करने वाला जनरेटर एक नया वर्ग बनाता है जो अपने ===
के अंदर ब्लॉक का उपयोग करता है विधि।
def exceptions_matching(&block)
Class.new do
def self.===(other)
@block.call(other)
end
end.tap do |c|
c.instance_variable_set(:@block, block)
end
end
begin
raise "FOOBAR: We're all doomed!"
rescue exceptions_matching { |e| e.message =~ /^FOOBAR/ }
puts "rescued!"
end
नमक का एक दाना
रूबी में कई अच्छी चालों की तरह, मैं बिल्कुल तय नहीं कर सकता कि यह सब पागलपन है या एक अच्छा विचार है। शायद यह दोनों का थोड़ा सा है। हालांकि मैं निश्चित रूप से यह सुझाव नहीं दूंगा कि आप पहली पसंद के रूप में इस तकनीक तक पहुंचें, मैं देख सकता हूं कि यह ऊपर की स्थितियों में कैसे उपयोगी होगा जहां आप गंभीरता के आधार पर अपवादों को बचाना चाहते हैं। किसी भी मामले में, यह आपके टूलबेल्ट में एक और टूल है!