ปัญหา आमใน Ruby คือ Error Messages — ใน Technical Terms เรียกว่า "Exceptions"
Exceptions อาจ คาดการณ์ได้ (Expected) เช่น File ที่มีบ้างคราวหาย, API Available ชั่วคราว — หรือ ไม่คาดคิด (Unexpected)
วันนี้เรียนจัดการ Expected Errors
ทำยังไง? มารู้จัก "begin" และ "rescue" ใน Ruby — 2 Keywords สำคัญ Handle Error Conditions
ทำงานยังไง? ก่อนเข้าใจว่า Ruby Programs อาจ Trigger Error หลายจุดระหว่างรัน
ตัวอย่าง:
- อ่านไฟล์ไม่มีอยู่
- หารเลขด้วยศูนย์
- Web Server SSL Certificate Expired
ตอน Error เกิดขึ้น... Ruby ไม่ Crash ทันที! — ได้ โอกาส Recover จาก Error เรียกว่า "Exception Handling"
Ruby ให้ Keywords Implement Error Recovery: begin & rescue — มาเรียนรู้!
วิธี Handle Ruby Exceptions
Wrap โค้ดที่อาจ Raise Exception ด้วย begin / rescue Block
ทำงานแบบนี้...
Section แรก (begin) = โค้ดที่จะรัน และอาจ Raise Exception
ตัวอย่าง:
begin
IO.sysopen('/dev/null')
rescue
# ...
end
พยายามเปิดไฟล์ sysopen — Exception ถ้าเปิดไม่ได้ — เวลาเหมาะสำหรับ rescue!
用 rescue บอกว่าตอน Exception เกิดขึ้น อยากให้เกิดอะไรขึ้น — Failure Mode อยู่ใต้ Control
ตัวอย่าง:
begin
IO.sysopen('/dev/null')
rescue
puts "Can't open IO device."
end
อยาก Log Error และอาจให้ Default Value — อย่า. Ignore. Errors.
Rescuing Multiple Exceptions
rescue รับ Optional Argument — คือ Exception Class ที่อยาก Rescue — ขึ้นอยู่กับ Code ที่รัน
สำหรับ IO:
Errno::ENOENT= File ไม่มีErrno::EACCES= Permission Error
จุดดี: Handle Multiple Exceptions ใน Block เดียวได้
แบบนี้:
begin
IO.sysopen('/dev/null')
rescue Errno::ENOENT
puts "File not found."
rescue Errno::EACCES
puts "Insufficient permissions, not allowed to open file."
end
อยาก Same Action สำหรับ Multiple Exceptions — ทำได้:
begin
IO.sysopen('/dev/null')
rescue Errno::ENOENT, Errno::EACCES
puts "There was an error opening the file."
end
เรียนต่อ!
Rescue Exceptions ภายใน Blocks และ Methods
ไม่บังคับ begin เสมอ — มี Cases ปล่อยได้
ที่ไหน? ภายใน Methods และ Blocks
ตัวอย่าง Method:
def get_null_device
IO.sysopen('/dev/null')
rescue Errno::ENOENT
puts "Can't open IO device."
end
Method Definition เองทำหน้าที่ begin — ปล่อยได้
Blocks ก็ได้:
["a.txt", "b.txt", "c.txt"].map do |f|
IO.sysopen(f)
rescue Errno::ENOENT
puts "Can't open IO device: #{f}."
end
อีก 1 วิธี 用 rescue โดยไม่ต้อง begin — มาดู
เข้าใจ Inline Rescue และทำไมถึงอันตราย
用 rescue Inline ได้ — บางกรณีหายาก Form นี้มีประโยชน์
ตัวอย่าง:
["a.txt", "b.txt", "c.txt"].select { |f| File.open(f) rescue nil }.map(&:size)
เปิดเฉพาะไฟล์ที่มีอยู่ ข้ามที่ไม่มี — ได้ Size ของไฟล์ที่มี — ไม่ Raise Exceptions
ทำไมทำ? โค้ดอยู่บรรทัดเดียว — นั่นแหละ
แตมี "Hidden Danger" — เพราะ Rescue ทุก Exceptions ที่สืบมาจาก StandardError (ส่วนใหญ่)
ทำไม NOT Good? ควร Handle Specific Exceptions แทน Broad Selection — หลีกเลี่ยงซ่อน Errors จากตัวเอง! Hidden Errors นำไปสู่ Strange Behavior และ Hard-to-debug Issues
Summary (สรุป)
คุณเรียนรู้ Errors ใน Ruby, Basic Exception Handling, และ Keywords rescue / begin
Share บทความถ้าHelpful 🙂 — ขอบคุณที่อ่านครับ!