Passing multiple error classes to ruby's rescue clause in a DRY fashion
You can use an array with the splat operator *
.
EXCEPTIONS = [FooException, BarException]
begin
a = rand
if a > 0.5
raise FooException
else
raise BarException
end
rescue *EXCEPTIONS
puts "rescued!"
end
If you are going to use a constant for the array as above (with EXCEPTIONS
), note that you cannot define it within a definition, and also if you define it in some other class, you have to refer to it with its namespace. Actually, it does not have to be a constant.
Splat Operator
The splat operator *
"unpacks" an array in its position so that
rescue *EXCEPTIONS
means the same as
rescue FooException, BarException
You can also use it within an array literal as
[BazException, *EXCEPTIONS, BangExcepion]
which is the same as
[BazException, FooException, BarException, BangExcepion]
or in an argument position
method(BazException, *EXCEPTIONS, BangExcepion)
which means
method(BazException, FooException, BarException, BangExcepion)
[]
expands to vacuity:
[a, *[], b] # => [a, b]
One difference between ruby 1.8 and ruby 1.9 is with nil
.
[a, *nil, b] # => [a, b] (ruby 1.9)
[a, *nil, b] # => [a, nil, b] (ruby 1.8)
Be careful with objects on which to_a
is defined, as to_a
will be applied in such cases:
[a, *{k: :v}, b] # => [a, [:k, :v], b]
With other types of objects, it returns itself.
[1, *2, 3] # => [1, 2, 3]
While the answer given by @sawa is technically right, I think it misuses Ruby's exception handling mechanism.
As the comment by Peter Ehrlich suggests (by pointing to an old blog post by Mike Ferrier), Ruby is already equipped with a DRY exception handler mechanism:
puts 'starting up'
begin
case rand(3)
when 0
([] + '')
when 1
(foo)
when 2
(3 / 0)
end
rescue TypeError, NameError => e
puts "oops: #{e.message}"
rescue Exception => e
puts "ouch, #{e}"
end
puts 'done'
By using this technique, we can access the exception object, which usually has some valuable information in it.