module Tins::Attempt
def attempt(opts = {}, &block)
Iff *reraise* is true the caught exception is reraised after running out
after a exponentially increasing duration of seconds.
seconds that is slept before giving up, and every attempt is retried
duration directly, in the latter case -*sleep* is the total number of
as seconds or a Numeric >= 0 or < 0. In the former case this is the
*sleep* is either a Proc returning a floating point number for duration
between attempts and catching the exception(s) in *exception_class*.
Attempts code in block *attempts* times, sleeping according to *sleep*
def attempt(opts = {}, &block) sleep = nil exception_class = StandardError prev_exception = nil if Numeric === opts attempts = opts else attempts = opts[:attempts] || 1 attempts >= 1 or raise ArgumentError, 'at least one attempt is required' exception_class = opts[:exception_class] if opts.key?(:exception_class) sleep = interpret_sleep(opts[:sleep], attempts) reraise = opts[:reraise] end return if attempts <= 0 count = 0 if exception_class.nil? begin count += 1 if block.call(count, prev_exception) return true elsif count < attempts sleep_duration(sleep, count) end end until count == attempts false else begin count += 1 block.call(count, prev_exception) true rescue *exception_class if count < attempts prev_exception = $! sleep_duration(sleep, count) retry end case reraise when Proc reraise.($!) when Exception.class raise reraise, "reraised: #{$!.message}" when true raise $!, "reraised: #{$!.message}" else false end end end end