Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Raise Object ใดๆ เป็น Ruby Exception: เทคนิคและ Best Practices

Ruby's raise syntax ให้ options สองอันสำหรับระบุ error type ที่ต้องการ raise โค้ดด้านล่างแสดง 3 วิธี raise RuntimeError

raise "hello" raise RuntimeError, "hello" raise RuntimeError.new("hello") # ...ทั้งหมด result ใน "RuntimeError: hello" 

ดีแต่ถ้าอยาก raise อะไรนอก exception? อยาก raise number? Ruby ไม่อนุญาต error message แบบนี้:

raise 1 # TypeError: exception class/object expected 

ข้อความนี้นำไปเชื่อว่า raise คาดหวัง exception class/object as parameter แต่มัน ผิด!

Introducing the exception Method

ถ้า raise foo raise method ไม่คาดหวัง foo เป็น exception object คาดหวังว่าจะได้ exception object เวลาเรียก foo.exception

สิ่งต้องจดจำ: ส่ง อะไรก็ได้ ให้ raise ได้ ตราบใดที่มันมี method ชื่อ exception ที่คืน exception

ถ้าอยาก monkeypatch Ruby number classes ให้ raise number ได้ ทำแบบนี้:

class Fixnum def exception RuntimeError.new("I'm number: #{ self }") end end raise 42 # ...results in raise_number.rb:7:in `<main>': I'm number: 42 (RuntimeError) 

Neat party trick แต่ useful ใน real life? Practical application หลักที่ผมเห็นคือแยก logic สร้าง exception จาก logic ตัดสินใจ raise exception Edge case แต่ดูยังไง:

A Possibly Practical Example

สมมติอยากอ่านบรรทัด data จาก IO ใดๆ network IO, file ไม่สำคัญ อยากอ่าน data check valid

ถ้า data ไม่ valid อยาก raise exception แต่ exception ต้อง tailored to input Network connection ต้อง debug info ต่าง local file ทำได้โดย custom exception methods สำหรับแต่ละ input class พล็อต pseudo-ruby:

# These three classes represent different kinds of IO with different exceptions. class NetworkConnection ... def exception NetworkConnectionError.new(url: url, ...) end end class LocalFile ... def exception FileError.new(path: path, ...) end end class UnixPipe ... def exception PipeError.new(...) end end def read_all(*items) items.each do |item| if item.readline != "foo" # We raise the item, which causes the appropriate exception class to be used. raise item end end end read_all(NetworkConnection.new(url: "example.com"), LocalFile.new("/something"), UnixPipe.new)