From: Robert Klemme Date: 2013-02-09T22:37:00+09:00 Subject: Re: confusion with "rescue" On Sat, Feb 9, 2013 at 1:07 PM, Love U Ruby 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 => # irb(main):041:0> class < #> 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/