A Ruby ‘tries’ method

Fiddling around on RefactorMyCode, which is good exercise.   Tj Holowaychuk posted a retry method, which appears itself to be a refactoring of the retryable method.

It didn’t look like it needed much trimming down, so I went to thinking about ways to make it better. Here’s what I came up with:

# Tries to perform an exception-prone operation.
#
# Options:
#   :ignoring - the exception that signals to try again.
#               Handles all Exceptions by default.
#
# Returns the result of &block the first time it runs without exceptions.
# If it threw an exception every time, it returns nil.

class Integer
  def tries options = {}, &block
    return if self < 1
    yield attempts ||= 1
  rescue options[:ignoring] || Exception
    retry if (attempts += 1) <= self
  end
end

What I did for it:

  • I figured it looked like it should be something parallel to the "times" method integers in Ruby implement (i.e. "3.times do ...") so I added it to Integer and renamed it appropriately (though I half think now that tries_to might have been a better name).
  • Renamed the :on option to :ignoring to make it a bit clearer what it does.
  • Added a check to make sure it was called with a positive integer (returning nil otherwise, same as if all tries fail).
  • Reversed the internal counter and gave it to yield to pass back to the &block, so you get an indicator of how many tries it's been so far, so you can do:

5.tries(:ignoring => ParticularException) do |i|
  puts "Try ##{i} at unreliable_operation..."
  unreliable_operation
end

It's probably not the most beautiful method out there, but I saw it posted in a couple of other places and figured I'd write it up.


Leave a Reply