From: "jeremyevans0 (Jeremy Evans)" Date: 2021-09-03T01:39:03+00:00 Subject: [ruby-core:105128] [Ruby master Feature#18145] Rescue by nested exception Issue #18145 has been updated by jeremyevans0 (Jeremy Evans). svoop (Sven Schwyn) wrote in #note-2: > @jeremyevans0 Nice one, thanks for the hint! I'll add this to a `ProviderError` and inherit from there. I guess this use case is too specific to add this `self.&` to `StandardError` or even `Exception` upstream? That's not for me to decide, but I would be against it. The need seems very limited to me, so the benefit seems low. Also, the approach requires allocating a new class for each exception where it needs to be tested, so it's suboptimal from a performance standpoint. A better performing approach would cache the equivalent of the `FindError & RestClient::NotFound` expression into a constant, and use that in the `rescue` clause. ---------------------------------------- Feature #18145: Rescue by nested exception https://bugs.ruby-lang.org/issues/18145#change-93540 * Author: svoop (Sven Schwyn) * Status: Open * Priority: Normal ---------------------------------------- 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: ```ruby 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: ```ruby 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): ```ruby 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? ```ruby begin Provider::Payment.find(123) rescue FindError & RestClient::NotFound ... rescue FindError ... end ``` -- https://bugs.ruby-lang.org/ Unsubscribe: