darthjee/core_ext

View on GitHub
lib/darthjee/core_ext/hash/deep_hash_constructor/setter.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Darthjee
  module CoreExt
    module Hash
      class DeepHashConstructor
        # @api private
        #
        # Class responsible for setting value localized inside hash
        #
        # @example Simple usage
        #   hash   = {}
        #   base   = 'person'
        #   setter = Darthjee::CoreExt::Hash::DeepHashConstructor::Setter.new(
        #     hash, base
        #   )
        #
        #   setter.set('age', 21)
        #
        #   hash # changed to {
        #        #   'person' => {
        #        #     'age' => 21,
        #        #   }
        #        # }
        class Setter
          # @param hash [Hash] hash to be changed
          # @param base_key [::String] base key of hash where
          #   subhash will be created
          def initialize(hash, base_key)
            @hash     = hash
            @base_key = base_key
          end

          # Sets a value in the correct key inside the hash
          #
          # @param key [::String,::NilClass] key where value will live
          # @param value [::Object] value to be set
          #
          # @return [::Object] value
          #
          # @example (see DeepHashConstructor)
          #
          # @example With Array index
          #   hash   = {}
          #   base   = 'person[0]'
          #   setter = Darthjee::CoreExt::Hash::DeepHashConstructor::Setter.new(
          #     hash, base
          #   )
          #
          #   setter.set('age', 21)
          #
          #   hash # changed to {
          #        #   'person' => [{
          #        #     'age' => 21,
          #        #   }]
          #        # }
          def set(key, value)
            return hash[base_key] = value unless key || index
            return array[index]   = value unless key

            sub_hash[key] = value
          end

          private

          # @private
          attr_reader :hash, :base_key

          # @private
          # Extract index of array from base_key
          #
          # @return [::NilClass,::Integer]
          def index
            return @index if instance_variable_defined?('@index')

            match = base_key.match(/\[([^)]+)\]/)
            return @index = nil unless match

            @index = match[1].to_i
          end

          # @private
          # Returns array that will receive value
          #
          # This array is only created / used when base_key
          # contains index
          #
          # @return [::Array]
          def array
            return @array if instance_variable_defined?('@array')

            key_without_index = base_key.tr("[#{index}]", '')

            @array = hash[key_without_index] ||= []
          end

          # @private
          # Returns sub hash that will receive the value
          #
          # This sub_hash is only build when key is not nil
          #
          # @return [::Hash]
          def sub_hash
            return array[index] ||= {} if index

            hash[base_key] ||= {}
          end
        end
      end
    end
  end
end