"Never rescue Exception in Ruby!"
อาจได้ยินมาก่อน คำแนะนำดีแตสับสนถ้ายังไม่ในวงใน มาแยก statement นี้ดู
คุณรู้ว่าใน Ruby rescue exceptions ได้แบบนี้:
begin do_something() rescue => e puts e # e is an exception object containing info about the error. end
Rescue specific errors โดยให้ classname ของ error:
begin do_something() rescue ActiveRecord::RecordNotFound => e puts e # Only rescues RecordNotFound exceptions, or classes that inherit from RecordNotFound end
ทุกประเภท exception ใน Ruby แค่ class ตัวอย่าง ActiveRecord::RecordNotFound แค่ชื่อ class ที่ follow conventions
สำคัญเพราะเวลา rescue RecordNotFound ก็ rescue exceptions ที่ inherit จากมันด้วย
ทำไมไม่ควร Rescue Exception
ปัญหา rescue Exception คือมัน rescue ทุก exception ที่ inherit จาก Exception ซึ่งคือ....ทั้งหมด!
ปัญหาเพราะมี exceptions บางตัวใช้ internally โดย Ruby ไม่เกี่ยวกับ app ของคุณ นำกลับมาจะทำให้壞事发生
ตัวใหญ่ๆ:
SignalException::Interrupt - rescue นี้ไม่สามารถ exit app ด้วย control-c
ScriptError::SyntaxError - นำ syntax errors กลับคืน
puts("Forgot something)fail silentlyNoMemoryError - อยากรู้ไหมว่า program รันต่อหลังใช้ RAM หมด ผมไม่อยากรู้
begin do_something() rescue Exception => e # Don't do this. This will swallow every single exception. Nothing gets past it. end
คุณไม่อยาก swallow system-level exceptions อยาก catch application-level errors จาก YOUR code
โชคดีมีวิธีง่าย
Rescue StandardError แทน
Exceptions ที่คุณควรสนใจ inherit จาก StandardError เพื่อนเก่า:
NoMethodError - raised ตอน invoke method ที่ไม่มี
TypeError - เกิดจาก
1 + ""RuntimeError - ใครลืม RuntimeError ได้ไง?
Rescue errors เหล่านี้ rescue StandardError เขียนแบบนี้ได้:
begin do_something() rescue StandardError => e # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. end
แต่ Ruby ทำให้ง่ายกว่านี้
เวลาไม่ระบุ exception class Ruby assume ว่าหมายถึง StandardError โค้ดด้านล่าง identical กับด้านบน:
begin do_something() rescue => e # This is the same as rescuing StandardError end
Custom Exceptions ควร Inherit จาก StandardError
หมายถึงอะไรถ้าสร้าง custom exceptions เอง?
ควร inherit จาก StandardError เสมอ และ อย่า inherit จาก Exception โดยเด็ดขาด Inherit จาก Exception แย่เพราะมันทำลาย expected behavior ของ rescue คนคิดว่ารescue all application-level errors แต่มันแค่ผ่านไป
class SomethingBad < StandardError end raise SomethingBad
The Exception Tree
เพราะ Ruby exceptions implemented ใน class hierarchy ดู layout ช่วยได้ นี่คือ exception classes ที่มาพร้อม Ruby standard library Third-party gems เช่น rails เพิ่ม exception classes เพิ่ม แต่ทุกตัว inherit จาก class ใน list นี้
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