"Ruby में कभी भी Exception रेस्क्यू न करें!"
शायद आपने यह पहले सुना है। यह अच्छी सलाह है, लेकिन यह काफी भ्रमित करने वाला है जब तक कि आप पहले से ही जानकार न हों। आइए इस कथन को तोड़ें और देखें कि इसका क्या मतलब है।
आप शायद जानते हैं कि Ruby में, आप अपवादों को इस तरह रेस्क्यू कर सकते हैं:
begin do_something() rescue => e puts e # e एक अपवाद ऑब्जेक्ट है जिसमें त्रुटि के बारे में जानकारी है। end
और आप त्रुटि के क्लासनाम प्रदान करके विशिष्ट त्रुटियों को रेस्क्यू कर सकते हैं।
begin do_something() rescue ActiveRecord::RecordNotFound => e puts e # केवल RecordNotFound अपवादों, या उन क्लासेस को रेस्क्यू करता है जो RecordNotFound से इनहेरिट करती हैं end
Ruby में हर प्रकार का अपवाद केवल एक क्लास है। उपरोक्त उदाहरण में, ActiveRecord::RecordNotFound केवल एक क्लास का नाम है जो कुछ कन्वेंशन का पालन करती है।
यह महत्वपूर्ण है क्योंकि जब आप `RecordNotFound` रेस्क्यू करते हैं, तो आप इससे इनहेरिट करने वाले किसी भी अपवाद को भी रेस्क्यू करते हैं।
आपको Exception रेस्क्यू क्यों नहीं करना चाहिए
`Exception` रेस्क्यू करने की समस्या यह है कि यह वास्तव में हर अपवाद को रेस्क्यू करता है जो `Exception` से इनहेरिट करता है। जो कि.... उनमें से सभी हैं!
यह एक समस्या है क्योंकि कुछ अपवाद हैं जिनका उपयोग Ruby आंतरिक रूप से करता है। उनका आपके ऐप से कोई लेना-देना नहीं है, और उन्हें निगलने से बुरी चीजें होंगी।
यहाँ कुछ बड़े हैं:
SignalException::Interrupt - यदि आप इसे रेस्क्यू करते हैं, तो आप कंट्रोल-सी दबाकर अपने ऐप से बाहर नहीं निकल सकते।
ScriptError::SyntaxError - सिंटैक्स त्रुटियों को निगलने का मतलब है कि `puts("Forgot something)` जैसी चीजें चुपचाप विफल हो जाएंगी।
NoMemoryError - जानना चाहते हैं कि जब आपका प्रोग्राम सारी RAM खत्म होने के बाद भी चलता रहता है तो क्या होता है? मुझे भी नहीं।
begin do_something() rescue Exception => e # ऐसा न करें। यह हर एक अपवाद को निगल लेगा। कुछ भी इसके पार नहीं जाता। end
मैं अनुमान लगा रहा हूँ कि आप वास्तव में इन सिस्टम-स्तरीय अपवादों में से किसी को भी निगलना नहीं चाहते। आप केवल अपनी एप्लिकेशन स्तर की सभी त्रुटियों को पकड़ना चाहते हैं। आपके कोड के कारण होने वाले अपवाद।
सौभाग्य से, ऐसा करने का एक आसान तरीका है।
इसके बजाय StandardError रेस्क्यू करें
आप जिन सभी अपवादों की परवाह करते हैं वे `StandardError` से इनहेरिट करते हैं। ये हमारे पुराने दोस्त हैं:
NoMethodError - जब आप किसी ऐसे मेथड को आह्वान करने का प्रयास करते हैं जो मौजूद नहीं है तो उठाया जाता है
TypeError - `1 + ""` जैसी चीजों के कारण होता है
RuntimeError - अच्छा पुराना RuntimeError कौन भूल सकता है?
इन जैसी त्रुटियों को रेस्क्यू करने के लिए, आप `StandardError` रेस्क्यू करना चाहेंगे। आप इसे ऐसा कुछ लिखकर कर सकते हैं:
begin do_something() rescue StandardError => e # केवल आपके ऐप के अपवाद निगले जाते हैं। SyntaxError जैसी चीजें अकेली छोड़ दी जाती हैं। end
लेकिन Ruby ने हमारे लिए इसे बहुत आसान बना दिया है।
जब आप बिल्कुल भी अपवाद क्लास निर्दिष्ट नहीं करते हैं, तो Ruby मान लेता है कि आप StandardError का मतलब है। इसलिए नीचे दिया गया कोड ऊपर दिए गए कोड के समान है:
begin do_something() rescue => e # यह StandardError रेस्क्यू करने के समान है end
कस्टम अपवादों को StandardError से इनहेरिट करना चाहिए
तो इसका आपके लिए क्या मतलब है यदि आप अपने स्वयं के कस्टम अपवाद बना रहे हैं?
इसका मतलब है कि आपको हमेशा `StandardError` से इनहेरिट करना चाहिए, और **कभी भी** `Exception` से नहीं। Exception से इनहेरिट करना बुरा है क्योंकि यह rescue के अपेक्षित व्यवहार को तोड़ता है। लोग सोचेंगे कि वे सभी एप्लिकेशन-स्तर की त्रुटियों को रेस्क्यू कर रहे हैं लेकिन आपका बस पार हो जाएगा।
class SomethingBad < StandardError end raise SomethingBad
अपवाद ट्री
चूंकि Ruby के अपवाद एक क्लास पदानुक्रम में लागू किए गए हैं, इसे laid out देखना मददगार हो सकता है। नीचे Ruby की मानक लाइब्रेरी के साथ आने वाली अपवाद क्लासेस की एक सूची है। Rails जैसे थर्ड-पार्टी जेम्स इस चार्ट में अतिरिक्त अपवाद क्लासेस जोड़ेंगे, लेकिन वे सभी इस सूची में किसी न किसी क्लास से इनहेरिट करेंगे।
Exception NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SignalException Interrupt StandardError ArgumentError IOError EOFError IndexError LocalJumpError NameError NoMethodError RangeError FloatDomainError RegexpError RuntimeError SecurityError SystemCallError SystemStackError ThreadError TypeError ZeroDivisionError SystemExit fatal