सबसे हालिया अपवाद प्राप्त करने में सक्षम होना अक्सर उपयोगी होता है, भले ही आपका कोड उस अपवाद के जीवनचक्र को नियंत्रित न करता हो। कल्पना करें कि आप अपने एप्लिकेशन में बेसिक क्रैश डिटेक्शन जोड़ना चाहते हैं। आप किसी अनकॉट अपवाद के परिणामस्वरूप होने वाले किसी भी क्रैश के बारे में अतिरिक्त जानकारी लॉग करना चाहेंगे।
पहला कदम एक हैंडलर जोड़ना है जो आपके एप्लिकेशन के बाहर निकलने पर चलता है। Ruby कर्नेल के `at_exit` मेथड के माध्यम से ऐसा करना सुपर आसान है।
at_exit puts "the app exited" end
लेकिन हम कैसे जान सकते हैं कि एग्जिट कॉलबैक को अपवाद के परिणामस्वरूप आह्वान किया गया था? खैर, Ruby क्रिप्टिक रूप से नामित `$!` ग्लोबल वेरिएबल प्रदान करता है। इसमें वर्तमान कॉल स्टैक में कहीं भी हुए सबसे हालिया उठाए गए अपवाद होते हैं।
`$!` का उपयोग यह पता लगाने के लिए करना तुच्छ है कि प्रोग्राम अपवाद के कारण बाहर निकल रहा है या नहीं। यह कुछ इस तरह दिखता है:
at_exit do save_error_to_log($!) if $! end
$! की सीमाएं
दुर्भाग्य से, `$!` मेथड केवल तभी काम करता है जब अपवाद वर्तमान कॉल स्टैक में कहीं हुआ हो। यदि आप एक अपवाद को रेस्क्यू करते हैं, तो रेस्क्यू क्लॉज के बाहर `$!` को एक्सेस करने का प्रयास करते हैं, तो आपको nil मिलेगा।
begin raise "x" rescue puts $! # => RuntimeError end puts $! # => nil
इसका मतलब है कि `$!` IRB जैसे शेल के अंदर काफी बेकार है। अक्सर IRB में, मैं एक मेथड चलाऊंगा और एक अपवाद प्राप्त करूंगा। कभी-कभी मैं उस अपवाद ऑब्जेक्ट को पकड़ना चाहूंगा। लेकिन `$!` इसके लिए काम नहीं करता।
irb(main):001:0> 1/0 ZeroDivisionError: divided by 0 from (irb):1:in `/' irb(main):002:0> $! => nil
PRY के साथ $! का समाधान
PRY अपने स्वयं के लोकल वेरिएबल, `_ex_` को जोड़कर `$!` की सीमाओं को पार करता है। इस वेरिएबल में सबसे हालिया अनकॉट अपवाद होता है।
[1] pry(main)> raise "hi" RuntimeError: hi from (pry):1:in `__pry__' [2] pry(main)> _ex_ => #<RuntimeError: hi>
PRY ऐसा करने में सक्षम है इसका कारण यह है कि PRY या IRB के अंदर वास्तव में कोई अनकॉट अपवाद नहीं हैं। शेल स्वयं अपवादों को पकड़ता है और उन्हें अच्छी तरह से फॉर्मेट किए गए त्रुटि संदेशों के रूप में प्रदर्शित करता है।
मैंने नीचे PRY स्रोत के प्रासंगिक भागों को कॉपी किया है। आप देख सकते हैं कि आपके कमांड का मूल्यांकन करने वाला कोड begin/rescue/end ब्लॉक के अंदर लपेटा गया है। जब एक रेस्क्यू करने योग्य अपवाद होता है, तो PRY अपवाद को self.last_exception में सेव करता है और बाद में इसे `_ex_` को असाइन कर दिया जाता है।
# PRY स्रोत से उद्धृत https://github.com/pry/pry/blob/623306966bfa86890ac182bc8375ec9699abe90d/lib/pry/pry_instance.rb#L273 begin if !process_command_safely(line) @eval_string << "#{line.chomp}\n" if !line.empty? || !@eval_string.empty? end rescue RescuableException => e self.last_exception = e result = e Pry.critical_section do show_result(result) end return end
English आवश्यक करें
शायद आप `$!` जैसे वेरिएबल नामों को आंखों पर थोड़ा कठोर पाते हैं? सौभाग्य से, Ruby में "English" नामक एक मॉड्यूल शामिल है जो कई ग्लोबल वेरिएबल के अंग्रेजी-भाषा संस्करण प्रदान करता है जो अन्यथा रोबोट शाप शब्दों की तरह दिखते हैं।
`$!` का पर्यायवाची `$ERROR_INFO` है। आप इसे जहां भी सामान्य रूप से `$!` का उपयोग करेंगे, उपयोग कर सकते हैं।
require "English" begin raise "x" rescue puts $ERROR_INFO # => RuntimeError end
और यद्यपि अधिकांश अन्य अंग्रेजी समकक्षों का इस ब्लॉग पोस्ट के विषय से कोई लेना-देना नहीं है, मैं उन्हें मज़े के लिए शामिल कर रहा हूँ। अंग्रेजी वेरिएबल बाईं ओर हैं। मूल दाईं ओर हैं।
| $ERROR_INFO | $! |
| $ERROR_POSITION | $@ |
| $FS | $; |
| $FIELD_SEPARATOR | $; |
| $OFS | $, |
| $OUTPUT_FIELD_SEPARATOR | $, |
| $RS | $/ |
| $INPUT_RECORD_SEPARATOR | $/ |
| $ORS | $\ |
| $OUTPUT_RECORD_SEPARATOR | $\ |
| $INPUT_LINE_NUMBER | $. |
| $NR | $. |
| $LAST_READ_LINE | $_ |
| $DEFAULT_OUTPUT | $> |
| $DEFAULT_INPUT | $< |
| $PID | $$ |
| $PROCESS_ID | $$ |
| $CHILD_STATUS | $? |
| $LAST_MATCH_INFO | $~ |
| $IGNORECASE | $= |
| $ARGV | $* |
| $MATCH | $& |
| $PREMATCH | $` |
| $POSTMATCH | $‘ |
| $LAST_PAREN_MATCH | $+ |