সাম্প্রতিক এক্সেপশন পাওয়া প্রায়শই উপকারী হয়, এমনকি যদি আপনার কোড সেই এক্সেপশনের লাইফসাইকেল কন্ট্রোল না করে। কল্পনা করুন আপনি আপনার অ্যাপ্লিকেশনে বেসিক ক্র্যাশ ডিটেকশন যোগ করতে চান। আপনি যেকোনো অক্যাচ্ট এক্সেপশনের ফলস্বরূপ হওয়া ক্র্যাশের বিষয়ে এক্সট্রা ইনফো লগ করতে চান।
প্রথম ধাপ হলো একটি হ্যান্ডলার যোগ করা যা আপনার অ্যাপ্লিকেশন এক্সিট করার সময় রান হবে। রুবি কার্নেলের at_exit মেথড দিয়ে এটা খুব সহজে করা যায়।
at_exit do
puts "the app exited"
end
কিন্তু আমরা কীভাবে জানব এক্সিট কলব্যাক এক্সেপশনের ফলস্বরূপ আহ্বান করা হয়েছে? রুবি криপ্টিক্যালি নামকৃত $! গ্লোবাল ভেরিয়েবল প্রদান করে। এতে করেন্ট কল স্ট্যাকে 어디서 কিনো발 हुई সাম্প্রতিক উত্থাপিত এক্সেপশন থাকে।
$! ব্যবহার করে প্রোগ্রামটি এক্সেপশনের কারণে এক্সিট হচ্ছে কিনা সেটা ডিটেক্ট করা তুচ্ছ। এটা দেখতে এরকম:
at_exit do
save_error_to_log($!) if $!
end
$!-এর সীমাবদ্ধতা
দুর্ভাগ্যবশত, $! মেথডটি শুধু কাজ করে যদি এক্সেপশন করেন্ট কল স্ট্যake কোথাও ঘটে। আপনি যদি একটি এক্সেপশন রেসকিউ করেন, তারপর রেসকিউ ক্লজের বাইরে থেকে $! অ্যাক্সেস করার চেষ্টা করেন, তবে আপনি নিল পাবেন।
begin
raise "x"
rescue
puts $! # => RuntimeError
end
puts $! # => nil
এটি মানে $! আইআরবির মতো একটি শেলের ভিতরে খুবই беспrays। প্রায়শই আইআরবিতে, আমি একটি মেথড রান করি এবং এক্সেপশন পাই। কখনো কখনো আমি সেই এক্সেপশন অবজেক্টটি পেতে চাই। কিন্তু $! এতে কাজ করে না।
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_
=> #
PRY এটা করতে পারে কারণ PRY বা আইআরবির ভিতরে কোনো অনক্যাচ্ট এক্সেপশন আসলে নেই। শেলটি নিজে এক্সেপশনগুলো ক্যাচ করে এবং সেগুলো সুন্দর ফরম্যাটেড এরর মেসেজ হিসেবে দেখায়।
আমি PRY সোর্সের প্রাসঙ্গিক অংশ নিচে কপি করেছি। আপনি দেখতে পাবেন যে আপনার কমান্ড ইভ্যালুয়েট করার কোডটি begin/rescue/end ব্লকের ভিতরে র্যাপড। যখন একটি রescuable এক্সেপশন ঘটে, 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
Require English
হয়তো আপনি $! এর মতো ভেরিয়েবল নাম একটু চোখে কাঁটা লাগতে পান? خوشবর, রুবি একটি মডিউল ইনক্লুড করে "English" নামে যা ইংরেজি-ভাষার ভার্সন প্রদান করে অনেক গ্লোবাল ভেরিয়েবলের যা অন্যথায় রোবট কাসওয়ার্ডের মতো দেখে।
$!-এর সিনোনিম হলো $ERROR_INFO। আপনি সেটা সেখানে ব্যবহার করতে পারেন যেনormalভাবে $! ব্যবহার করতেন।
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 | $+ |