Sha256: 51ee613f501ef745028119a0ebe75f209c148f34cfd92735dfe246e7593eb0bc

Contents?: true

Size: 1.55 KB

Versions: 2

Compression:

Stored size: 1.55 KB

Contents

module BusinessFlow
  # Isolate the logic around invoking a 'callable' -- a symbol representing a
  # method, a symbol representing another class which implements .call, or a
  # proc/lambda
  class Callable
    def initialize(callable, metaclass)
      @metaclass = metaclass
      @callable = callable
      check_callable
    end

    def call(instance, inputs)
      cached_proc.call(instance, inputs)
    end

    private

    # :reek:ManualDispatch Look reek I don't know what you want me to do.
    def check_callable
      if @callable.is_a?(Proc)
        @cached_proc = proc do |instance, inputs|
          instance.instance_exec(inputs, &@callable)
        end
      elsif @callable.respond_to?(:call)
        @cached_proc = proc { |_, inputs| @callable.call(inputs) }
      elsif !@callable.is_a?(Symbol)
        raise ArgumentError, 'callable must be a symbol or respond to #call'
      end
    end

    def cached_proc
      @cached_proc ||=
        if @metaclass.method_defined?(@callable) ||
           @metaclass.private_method_defined?(@callable)
          proc { |instance, _| instance.send(@callable) && nil }
        else
          @callable = lookup_callable ||
                      raise(NameError, "undefined constant #{@klass}")
          proc { |_, inputs| @callable.call(inputs) }
        end
    end

    def lookup_callable
      constant_name = @callable.to_s.camelcase
      @metaclass.parents.each do |parent|
        begin
          break parent.const_get(constant_name)
        rescue NameError
          next
        end
      end
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
business_flow-0.3.0 lib/business_flow/callable.rb
business_flow-0.2.0 lib/business_flow/callable.rb