Computer >> Máy Tính >  >> Lập trình >> Ruby

Cách nâng cao bất kỳ đối tượng nào dưới dạng ngoại lệ Ruby

Cú pháp tăng của Ruby cung cấp cho bạn một số tùy chọn để chỉ định loại lỗi bạn muốn nêu ra. Trong đoạn mã dưới đây, tôi đã chỉ ra ba cách để tăng RuntimeError.

raise "hello"
raise RuntimeError, "hello"
raise RuntimeError.new("hello")

# ...all of the above result in "RuntimeError: hello"

Điều đó thật tuyệt, nhưng điều gì sẽ xảy ra khi tôi muốn nâng cao thứ gì đó không phải là ngoại lệ? Điều gì sẽ xảy ra nếu tôi muốn tăng một số? Chà, Ruby sẽ không để tôi. Tôi nhận được một thông báo lỗi như sau:

raise 1
# TypeError: exception class/object expected

Bây giờ thông báo này có thể khiến bạn tin rằng nâng cao mong đợi một lớp / đối tượng ngoại lệ như một tham số. Nhưng điều đó không chính xác!

Giới thiệu exception phương pháp

Nếu bạn raise foo phương thức raise không mong đợi foo là một đối tượng ngoại lệ. Nó hy vọng rằng nó sẽ nhận được một đối tượng ngoại lệ bất cứ khi nào nó gọi foo.exception .

Điều cần nhớ là bạn có thể chuyển BẤT CỨ THỨ NÀO để tăng, miễn là nó có một phương thức gọi là ngoại lệ trả về một ngoại lệ.

Vì vậy, nếu bạn muốn, bạn có thể bắt cặp các lớp số của ruby ​​để cho phép bạn nâng lên một con số. Đây là những gì có thể trông giống như:

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)

Đây là một mẹo nhỏ trong bữa tiệc, nhưng nó có bao giờ hữu ích trong cuộc sống thực không? Ứng dụng thực tế chính mà tôi thấy cho kỹ thuật này là tách logic cần thiết để xây dựng ngoại lệ khỏi logic quyết định nâng cao ngoại lệ. Đây chắc chắn là một trường hợp phức tạp. Nhưng hãy xem nó có thể trông như thế nào.

Một ví dụ có thể thực tế

Giả sử tôi muốn đọc một dòng dữ liệu từ một số loại IO. Nó có thể là IO mạng, nó có thể là một tập tin. Nó không thực sự quan trọng. Tôi chỉ muốn đọc dữ liệu và xem nó có hợp lệ không.

Nếu dữ liệu tôi đọc không hợp lệ, tôi muốn đưa ra một ngoại lệ. Nhưng ngoại lệ cần được điều chỉnh cho phù hợp với đầu vào. Kết nối mạng cần có thông tin gỡ lỗi khác với tệp cục bộ. Tôi có thể làm điều đó bằng cách cung cấp các phương thức ngoại lệ tùy chỉnh cho từng loại lớp đầu vào. Đây là một số giả ruby ​​cho thấy nó có thể trông như thế nào.

# 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)