On Sat, Feb 9, 2013 at 1:07 PM, Love U Ruby <lists / ruby-forum.com> wrote:
> 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..."
>
> This is mainly used for "===" overloading when rescue would perform
> matching .

That approach does not work:

irb(main):014:0> module M
irb(main):015:1> def ===(e) /test/ === e.message end
irb(main):016:1> end
=> nil
irb(main):017:0> begin; raise "test"; rescue M => e; p "caught";
rescue Exception => e; p "uncaught"; else p "nothing" end
"uncaught"
=> "uncaught"

> That is far thing for me. can anyone help me to understand what the "def
> ... end" part is doing?

It defines a new anonymous module which delegates its instance method
=== to instance pattern.  It uses a closure which references pattern.

> I am totally uncomfortable with the syntax. So break it and help me to
> understand what is doing.

class << m; self; end yields the singleton class of m - today we can
simply use m.singleton_class instead.

Then #instance_eval is used to be able to invoke the private method
#define_method.  An alternative way would be

m.singleton_class.send(:define_method, :===) { pattern === e.message }

The idea seems to be that rescue works the same as case, i.e. by using
=== of the instances passed to do matching.  But it doesn't (see
above, where I manually recreated that situation).  Instead rescue
checks whether the class named is a superclass of the exception
caught.  You cannot even use Class#> for that:

irb(main):040:0> o = Object.new
=> #<Object:0x802be35c>
irb(main):041:0> class <<o; include Comparable; end
=> #<Class:#<Object:0x802be35c>>
irb(main):042:0> def o.<=>(e) /test/ =~ e.message ? 1 : -1 end
=> nil
irb(main):043:0> begin; raise "test"; rescue o => e; p e; rescue => e;
p "fail" end
"fail"
=> "fail"

A more successful approach is this

begin
rescue => e
  case e.message
  when /socket/
    puts "socket error"
  when /file/
    puts "file error"
  else
    puts "no idea: #{e.message}"
  end
end

Kind regards

robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/