jspillers/simple_service

View on GitHub
lib/simple_service.rb

Summary

Maintainability
A
25 mins
Test Coverage
A
92%
require 'simple_service/result'
require 'simple_service/configuration'
require 'simple_service/version'

module SimpleService
  def self.included(klass)
    klass.extend ClassMethods
    klass.include InstanceMethods
    self.configure
  end

  class << self
    attr_accessor :configuration
  end

  def self.configure
    self.configuration ||= Configuration.new
    yield(configuration) if block_given?
  end

  module ClassMethods
    def command(command_name)
      @commands ||= []
      @commands << command_name
    end

    def commands(*args)
      @commands ||= []
      @commands += args
    end

    def call(kwargs={})
      service = self.new

      # if kwargs is a result obj then pull its hash out via #value
      service.result.value = kwargs.is_a?(Result) ? kwargs.value : kwargs

      get_commands(service).each do |cmnd|
        service = execute_command(cmnd, service)
        break if service.result.failure?
      end

      service.result
    end

    def get_commands(service)
      if !@commands.nil? && @commands.any?
        @commands
      elsif service.respond_to?(:call)
        [:call]
      else
        raise "No commands defined for #{self.to_s}, define at least one " \
          'command or implement the #call method'
      end
    end

    def execute_command(cmnd, service)
      service.current_command = cmnd

      command_output = if cmnd.is_a?(Class)
        cmnd.call(service.result.value)
      elsif cmnd.is_a?(Symbol)
        if service.method(cmnd).arity.zero?
          service.public_send(cmnd)
        else
          service.public_send(cmnd, **service.result.value)
        end
      end

      if command_output.is_a?(Result)
        service.result.append_result(command_output)
      end

      service
    end
  end

  module InstanceMethods
    def result
      @result ||= Result.new
    end

    def current_command
      @current_command
    end

    def current_command=(cmnd)
      @current_command = cmnd
    end

    def commands
      self.class.instance_variable_get('@commands') || []
    end

    def success(result_value)
      result.success!(self.class, current_command, result_value)
    end

    def failure(result_value)
      result.failure!(self.class, current_command, result_value)
    end
  end
end