class BusinessFlow::Callable

Isolate the logic around invoking a 'callable' – a symbol representing a method, a symbol representing another class which implements .call, or a proc/lambda

Public Class Methods

new(callable) click to toggle source
# File lib/business_flow/callable.rb, line 6
def initialize(callable)
  @callable = callable
  check_callable
end

Public Instance Methods

call(instance, inputs) click to toggle source

:reek: ManualDispatch At this stage @callable is a symbol and is either a method or a constant. Checking respond_to? is easier and faster than generating a NoMethodError and catching it.

# File lib/business_flow/callable.rb, line 14
def call(instance, inputs)
  if instance.respond_to?(@callable, true)
    send_callable(instance, inputs)
  else
    @callable = lookup_callable(instance) ||
                raise(NameError, "undefined constant #{@callable}")
    check_callable
    call(instance, inputs)
  end
end
to_s() click to toggle source
# File lib/business_flow/callable.rb, line 25
def to_s
  @callable.to_s
end

Private Instance Methods

call_callable() click to toggle source
# File lib/business_flow/callable.rb, line 62
def call_callable
  case @callable.method(:call).arity
  when 1, -1
    single_inputs_callable
  when 0
    zero_inputs_callable
  else two_inputs_callable
  end
end
check_callable() click to toggle source
# File lib/business_flow/callable.rb, line 40
def check_callable
  if @callable.is_a?(Proc)
    proc_callable
  else
    call_callable
  end
rescue NameError
  unless @callable.is_a?(Symbol)
    raise ArgumentError, 'callable must be a symbol or respond to #call'
  end
end
lookup_callable(first_instance) click to toggle source
# File lib/business_flow/callable.rb, line 96
def lookup_callable(first_instance)
  constant_name = @callable.to_s.camelcase
  first_instance.class.parents.each do |parent|
    begin
      return parent.const_get(constant_name)
    rescue NameError
      next
    end
  end
  nil
end
proc_callable() click to toggle source
# File lib/business_flow/callable.rb, line 52
def proc_callable
  instance_eval %{
    def call(instance, inputs)
      instance.instance_exec(
        #{@callable.arity.zero? ? '' : 'inputs, '}&@callable
      )
    end
  }, __FILE__, __LINE__ - 6
end
send_callable(instance, inputs) click to toggle source
# File lib/business_flow/callable.rb, line 31
def send_callable(instance, inputs)
  instance_eval %{
    def call(instance, _inputs)
      instance.send(@callable)
    end
  }, __FILE__, __LINE__ - 4
  call(instance, inputs)
end
single_inputs_callable() click to toggle source
# File lib/business_flow/callable.rb, line 72
def single_inputs_callable
  instance_eval %{
    def call(_instance, inputs)
      @callable.call(inputs)
    end
  }, __FILE__, __LINE__ - 4
end
two_inputs_callable() click to toggle source
# File lib/business_flow/callable.rb, line 88
def two_inputs_callable
  instance_eval %{
    def call(instance, inputs)
      @callable.call(instance, inputs)
    end
  }, __FILE__, __LINE__ - 4
end
zero_inputs_callable() click to toggle source
# File lib/business_flow/callable.rb, line 80
def zero_inputs_callable
  instance_eval %{
    def call(_instance, _inputs)
      @callable.call
    end
  }, __FILE__, __LINE__ - 4
end