Ruby style question from a newby: exceptions


#1

Hi,

Any hints on the best way to catch exceptions from the point of view of
good style for the following?


puts “Create connection…”
imap = IMAP.new(‘sslmail.somewhere.com’, 993, true)
puts “Capabilities: cap = #{imap.capability().join(” “)}”
puts “Authenticate…”
logged_in = false

begin
imap.authenticate(‘CRAM-MD5’, ‘myname’, ‘secret’)
logged_in = true
rescue Net::IMAP::NoResponseError => e
puts " Failed, #{e}"
end

puts “Try Login…”
if ! logged_in then
begin
imap.login(‘myname’, ‘secret’)
logged_in = true
rescue
puts " Failed, #{e}"
end
end

What am I trying to do and what don’t I like? Basically I want to try a
sequence of things until one of them works — first I want to use the
authenticate method and if that fails to use the login method. Each of
these methods indicates failure by raising an exception. I want to log
each failure (because I’m experimenting with the library at this
stage). In this example I want to log each failure and on failure I
want to cacade to an alternative strategy.

How could this code be better written so that it is easier to read and
understand the flow of the code? Would it be possible to achieve
something like the following?


exceptions = until_success
{ imap.authenticate … },
{ imap.login … }

if exceptions.failed then
puts “Unable to login: #{exceptions.join(’\n’)}”
else
puts “Login successfull. Record of unsuccessfull attempts: \n
#{exceptions.join(”\n “)}”
end

with a function until_success taking a sequence of blocks as arguments?

regards,

Richard.


#2

Is the following irb session informative?

irb(main):013:0> c = 0
irb(main):014:0> begin
irb(main):015:1*   p c
irb(main):016:1>   raise
irb(main):017:1> rescue
irb(main):018:1>   c += 1
irb(main):019:1>   retry if c < 5
irb(main):020:1> end
1
2
3
4
=> nil

#3

YANAGAWA Kazuhisa wrote:

irb(main):019:1>   retry if c < 5

Hi Richard,

Here’s a variation on that theme:

#--------------------------------------------------------

METHOD_Q = [ [:aaa, TypeError],
[:bbb, NoMethodError],
[:ccc, ArgumentError],
[:ddd, NameError],
].freeze

def log(item); puts “LOG: #{item}”; end

def aaa; 11 + ‘Two Two’; end
def bbb; 12.sort; end
def ccc; [].each(13) {}; end
def ddd
puts “4th attempt”

NOCONST # <— uncomment

end

catch(:done) do
stack = METHOD_Q.dup
begin
meth, exc = stack.shift
unless meth
log “Tried everything :(”
throw(:done)
end
send(meth)
log “Success at last!”
rescue exc => e
log “#{meth} error”
log “^ #{e.message}”
retry
end
end

=begin

LOG: aaa error
LOG: ^ String can’t be coerced into Fixnum
LOG: bbb error
LOG: ^ undefined method `sort’ for 12:Fixnum
LOG: ccc error
LOG: ^ wrong number of arguments (1 for 0)
4th attempt
LOG: Success at last!

=end
#--------------------------------------------------------

daz