darthjee/azeroth

View on GitHub
lib/azeroth/decorator/key_value_extractor.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

module Azeroth
  class Decorator
    # @api private
    #
    # Class responsible to extract the value for an attribute
    #
    # The value is extracted by sending a method
    # call to the decorator
    #
    # A decorator is infered for the value / attribute
    # or used from the options given
    class KeyValueExtractor < Sinclair::Model
      initialize_with(:decorator, :attribute, :options)
      # @param decorator [Decorator] decorator object
      # @param attribute [Symbol] attribute to be used on output hash
      # @param options [Decorator::Options] decoration options
      # @option options if [Proc,Symbol] conditional to be
      #   checked when exposing field
      #   (see {Decorator::Options#if})

      # Return hash for attribute
      #
      # @return [Hash] hash in the format
      #   +{ attribute => decorated_value }+
      def as_json
        return {} unless add_attribute?

        key = options.as || attribute

        {
          key.to_s => json_value
        }
      end

      private

      # @method decorator
      # @api private
      # @private
      #
      # decorator with object to be decorated
      #
      # @return [Decorator]

      # @method attribute
      # @api private
      # @private
      #
      # attribute to be exposed
      #
      # @return [Symbol]

      # @method options
      # @api private
      # @private
      #
      # exposing options
      #
      # @return [Decorator::Options]

      # @private
      #
      # returns the value ready to be transformed into json
      #
      # @return [Object]
      def json_value
        decorator_class(value).new(value).as_json
      end

      # @private
      # Retruns the value extracted from decorator
      #
      # @return [Object]
      def value
        @value ||= decorator.public_send(attribute)
      end

      # @private
      #
      # Finds the correct decorator class for a value
      #
      # @return [Class<Decorator>]
      def decorator_class(object)
        decorator_from_options || decorator_class_for(object)
      end

      # @private
      #
      # returns decorator defined in options
      #
      # @return [Class<Decorator>, NilClass]
      def decorator_from_options
        return options.decorator if options.decorator_defined?

        Azeroth::DummyDecorator unless options.decorator
      end

      # @private
      #
      # Finds the correct decorator class for a value
      #
      # @return [Class<Decorator>]
      def decorator_class_for(object)
        return object.class::Decorator unless object.is_a?(Enumerable)

        decorator_class_for(object.first)
      rescue NameError
        Azeroth::DummyDecorator
      end

      # @private
      #
      # Check if an attribute should be added to the hash
      #
      # @return [Object] result of method call from decorator
      def add_attribute?
        conditional = options.if
        return true unless conditional.present?

        block = proc(&conditional)

        block.call(decorator)
      end
    end
  end
end