class ReeStd::Retry

def calculate_retry_interval

def calculate_retry_interval
  current_interval = @interval * (@backoff_factor ** @current_attempt)
  [@max_interval, current_interval].min
end

def call(&block)

def call(&block)
  block.call
rescue => e
  raise unless match_error?(e)
  raise unless has_attempts?
  @retry_block.call(@current_attempt, e)
  Kernel.sleep(calculate_retry_interval)
  increment_attemt!
  retry
end

def has_attempts?

def has_attempts?
  @current_attempt < @max
end

def increment_attemt!

def increment_attemt!
  @current_attempt += 1
end

def initialize(max:, **opts)

def initialize(max:, **opts)
  @max = max
  @current_attempt = 0
  @interval = opts.fetch(:interval, 1)
  @max_interval = opts.fetch(:max_interval, Float::INFINITY)
  @backoff_factor = opts.fetch(:backoff_factor, 1)
  @exceptions = opts.fetch(:exceptions) { [StandardError].freeze }
  @retry_block = opts.fetch(:retry_block, Proc.new {})
  @retry_if = opts.fetch(:retry_if, Proc.new { true })
end

def match_error?(e)

def match_error?(e)
  puts @retry_if.call(e)
  @retry_if.call(e) && @exceptions.any? { e.is_a? _1 }
end