Passing multiple error classes to ruby's rescue clause in a DRY fashion

↘锁芯ラ 提交于 2019-11-28 03:03:22
sawa

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]

I just ran into this issue and found an alternate solution. In the case your FooException and BarException are all going to be custom exception classes and particularly if they are all thematically related, you can structure your inheritance hierarchy such that they will all inherit from the same parent class and then rescue only the parent class.

For example I had three exceptions: FileNamesMissingError,InputFileMissingError, and OutputDirectoryError that I wanted to rescue with one statement. I made another exception class called FileLoadError and then set up the above three exceptions to inherit from it. I then rescued only FileLoadError.

Like this:

class FileLoadError < StandardError
end

class FileNamesMissingError < FileLoadError
end

class InputFileMissingError < FileLoadError
end

class OutputDirectoryError < FileLoadError
end

[FileNamesMissingError,
 InputFileMissingError,
 OutputDirectoryError].each do |error| 
   begin  
     raise error
   rescue FileLoadError => e
     puts "Rescuing #{e.class}."
   end 
end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!