[#105450] [Ruby master Feature#18228] Add a `timeout` option to `IO.copy_stream` — "byroot (Jean Boussier)" <noreply@...>
SXNzdWUgIzE4MjI4IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJ5cm9vdCAoSmVhbiBCb3Vzc2llciku
11 messages
2021/09/27
[ruby-core:105128] [Ruby master Feature#18145] Rescue by nested exception
From:
"jeremyevans0 (Jeremy Evans)" <noreply@...>
Date:
2021-09-03 01:39:03 UTC
List:
ruby-core #105128
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: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>