module FiniteMachine::Catchable

A mixin to allow for specifying error handlers

Public Class Methods

included(base) click to toggle source

Extends object with error handling methods

@api private

# File lib/finite_machine/catchable.rb, line 9
def self.included(base)
  base.module_eval do
    attr_threadsafe :error_handlers, default: []
  end
end

Public Instance Methods

catch_error(exception) click to toggle source

Catches error and finds a handler

@param [Exception] exception

@return [Boolean]

true if handler is found, nil otherwise

@api public

# File lib/finite_machine/catchable.rb, line 50
def catch_error(exception)
  if handler = handler_for_error(exception)
    handler.arity.zero? ? handler.call : handler.call(exception)
    true
  end
end
handle(*exceptions, &block) click to toggle source

Rescue exception raised in state machine

@param [Array] exceptions

@example

handle TransitionError, with: :pretty_errors

@example

handle TransitionError do |exception|
  logger.info exception.message
  raise exception
end

@api public

# File lib/finite_machine/catchable.rb, line 29
def handle(*exceptions, &block)
  options = exceptions.last.is_a?(Hash) ? exceptions.pop : {}

  unless options.key?(:with)
    if block_given?
      options[:with] = block
    else
      raise ArgumentError, "Need to provide error handler."
    end
  end
  evaluate_exceptions(exceptions, options)
end

Private Instance Methods

evaluate_exceptions(exceptions, options) click to toggle source

Check if exception inherits from Exception class and add to error handlers

@param [Array] exceptions

@param [Hash] options

@api private

# File lib/finite_machine/catchable.rb, line 102
def evaluate_exceptions(exceptions, options)
  exceptions.each do |exception|
    key = extract_exception_name(exception)
    error_handlers << [key, options[:with]]
  end
end
evaluate_handler(handler) click to toggle source

Executes given handler

@api private

# File lib/finite_machine/catchable.rb, line 82
def evaluate_handler(handler)
  case handler
  when Symbol
    target.method(handler)
  when Proc
    if handler.arity.zero?
      -> { instance_exec(&handler) }
    else
      ->(exception) { instance_exec(exception, &handler) }
    end
  end
end
extract_const(class_name) click to toggle source

Find constant in state machine namespace

@param [String] class_name

@api private

# File lib/finite_machine/catchable.rb, line 73
def extract_const(class_name)
  class_name.split("::").reduce(FiniteMachine) do |constant, part|
    constant.const_get(part)
  end
end
extract_exception_name(exception) click to toggle source

Extract exception name

@param [Class,Exception,String] exception

@api private

# File lib/finite_machine/catchable.rb, line 114
def extract_exception_name(exception)
  if exception.is_a?(Class) && exception <= Exception
    exception.name
  elsif exception.is_a?(String)
    exception
  else
    raise ArgumentError, "#{exception} isn't an Exception"
  end
end
handler_for_error(exception) click to toggle source
# File lib/finite_machine/catchable.rb, line 59
def handler_for_error(exception)
  _, handler = error_handlers.reverse.find do |class_name, _|
    klass = FiniteMachine.const_get(class_name) rescue nil
    klass ||= extract_const(class_name)
    exception <= klass
  end
  evaluate_handler(handler)
end