We can put a class or module after a rescue statement, but in the code below, I see a method following rescue, which does not fit into this pattern. How is it working and how is it producing the output it has been designed to show?
def errors_with_message(pattern)
# Generate an anonymous "matcher module" with a custom threequals
m = Module.new
(class << m; self; end).instance_eval do
define_method(:===) do |e|
pattern === e.message
end
end
m
end
puts "About to raise"
begin
raise "Timeout while reading from socket"
rescue errors_with_message(/socket/)
puts "Ignoring socket error"
end
puts "Continuing..."
Output
About to raise
Ignoring socket error
Continuing...
Rescue requires a class or a module, true. So, that method creates an anonymous module with special behaviour. You see, when
rescuesearches for a handler, it applies===operator to exception classes/modules you provided, passing as an argument the actual exception.So, if
StandardError(or one of its descendants) was raised, the first handler will be skipped and second handler will be matched.Now, the module from
errors_with_messageis special. It redefines threequals operator to match on exception message. So, if an error was raised and its message contains word “socket”, this handler will match. Cool trick, huh?