myfreecomm/billimatic-client-ruby

View on GitHub
lib/billimatic/resources/base.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "billimatic/resources/hooks"

module Billimatic
  module Resources
    class Base
      include Wisper::Publisher
      extend Hooks
      attr_accessor :http

      def self.crud(*args)
        @crud ||= args
      end

      def initialize(http)
        @http = http
      end

      def collection_name
        @collection_name ||= underscore_pluralized_klass_name
      end

      def parsed_body(response)
        MultiJson.load(response.body)
      rescue MultiJson::ParseError
        {}
      end

      def create(params)
        crud_request do
          http.post(resource_base_path, { body: params }) do |response|
            respond_with_entity(response)
          end
        end
      end

      def show(id)
        crud_request do
          http.get("#{resource_base_path}/#{id}") do |response|
            respond_with_entity(response)
          end
        end
      end

      def list
        crud_request do
          http.get(resource_base_path) do |response|
            respond_with_collection(response)
          end
        end
      end

      def list_by_organization(id)
        http.get("/organizations/#{id}#{resource_base_path}") do |response|
          respond_with_collection response
        end
      end

      def show_by_organization(organization_id, entity_id)
        http.get(
          "/organizations/#{organization_id}#{resource_base_path}/#{entity_id}"
        ) { |response| respond_with_entity response }
      end

      def destroy(id)
        crud_request do
          http.delete("#{resource_base_path}/#{id}") do |response|
            response.code == 204
          end
        end
      end

      def update(id, params)
        crud_request do
          http.put("#{resource_base_path}/#{id}", { body: params }) do |response|
            respond_with_entity(response)
          end
        end
      end

      notify :create, :destroy

      protected

      def crud_request
        method = caller_locations(1,1)[0].label
        if self.class.crud.include?(:all) || self.class.crud.include?(method.to_sym)
          yield
        else
          raise RuntimeError, "#{base_klass} do not implement the #{method} method"
        end
      end

      def respond_with_collection(response, class_name = base_klass)
        parsed_body(response)[collection_name].map do |item|
          entity_klass(class_name).new(item)
        end
      end

      def respond_with_entity(response, naked_klass = entity_klass)
        naked_klass.new(parsed_body(response)[underscored_klass_name])
      end

      def respond_with_openstruct(response)
        OpenStruct.new(MultiJson.load(response.body))
      end

      def resource_base_path
        @resource_base_path ||= "/#{collection_name}"
      end

      def base_klass
        @base_klass ||= self.class.name.split('::').last
      end

      def entity_klass(class_name = base_klass)
        @entity_klass ||= Billimatic::Entities.const_get(class_name.to_sym)
      end

      def underscore_pluralized_klass_name
        "#{underscored_klass_name}s"
      end

      def underscored_klass_name
        base_klass.gsub(/(.)([A-Z])/, '\1_\2').downcase
      end
    end
  end
end