Project

General

Profile

Actions

Feature #18145

closed

Rescue by nested exception

Added by svoop (Sven Schwyn) about 3 years ago. Updated about 3 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:105125]

Description

The introduction of Exception#cause helps a lot when debugging nested errors.

Same goes for wrapped errors. I'm not really sure whether such wrapped errors are an advisable pattern to begin with, feel free to comment on this, but I've used it in a couple of vendored gems dealing with payment providers.

Here's some simplified code to illustrate. The Payment class deals with all the gory things such as authorization, coercion or API quirks. A simplified version might look like this:

require 'rest_client'

module Provider
  class FindError < StandardError; end

  class Payment
    attr_reader :id, :amount

    private_class_method :new

    def initialize(id, amount)
      @id, @amount = id, amount
    end

    def self.find(id)
      response = RestClient.get('https://api.provider.com/payments', params: { id: id })
      body = JSON.parse(response.body)
      new(id, body.fetch('amount'))
    rescue
      raise FindError
    end
  end
end

You can easily rescue from anything going wrong when loading a payment:

begin
  Provider::Payment.find(123)
rescue FindError
  ...
end

However, you might want to rescue differently for some specific causes (e.g. not found) but not for others (e.g. timeout):

begin
  Provider::Payment.find(123)
rescue FindError => error
  if error.cause.instance_of? RestClient::NotFound
    ...
  else
    ...
  end
end

How about allowing to rescue by nested exception with a syntax like?

begin
  Provider::Payment.find(123)
rescue FindError & RestClient::NotFound
  ...
rescue FindError
  ...
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0