- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/shared/many"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Refinements
           
        
      
        
          
- 
            
            
              
            
            
  # Provides additional enhancements to the Hash primitive.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Hash
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    refine ::Hash.singleton_class do
           
        
      
        
          
- 
            
              5
            
            
              
            
            
      def infinite = new { |nascence, lacuna| nascence[lacuna] = new(&nascence.default_proc) }
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              2
            
            
              
            
            
      def with_default(value) = new { |nascence, lacuna| nascence[lacuna] = value }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    refine ::Hash do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      import_methods Shared::Many
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              14
            
            
              
            
            
      def compress = compact.delete_if { |_key, value| value.respond_to?(:empty?) && value.empty? }
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def compress!
           
        
      
        
          
- 
            
              19
            
            
              
            
            
        delete_if { |_key, value| value.respond_to?(:empty?) && value.empty? }
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        compact!
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_merge other
           
        
      
        
          
- 
            
              12
            
            
              
            
            
        clazz = self.class
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              12
            
            
              
            
            
        merge other do |_key, this_value, other_value|
           
        
      
        
          
- 
            
              14
            
            
              
                
                  then: 6
                
              
            
            
          if this_value.is_a?(clazz) && other_value.is_a?(clazz)
           
        
      
        
          
- 
            
              6
            
            
              
            
            
            this_value.deep_merge other_value
           
        
      
        
          
- 
            
            
              
                
                  else: 8
                
              
            
            
          else
           
        
      
        
          
- 
            
              8
            
            
              
            
            
            other_value
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_merge!(other) = replace(deep_merge(other))
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_stringify_keys = recurse(&:stringify_keys)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_stringify_keys! = replace(deep_stringify_keys)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_symbolize_keys = recurse(&:symbolize_keys)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def deep_symbolize_keys! = replace(deep_symbolize_keys)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def diff other
           
        
      
        
          
- 
            
              5
            
            
              
                
                  then: 3
                
              
                
                  else: 2
                
              
            
            
        return differences_from other if other.is_a?(self.class) && keys.sort! == other.keys.sort!
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              7
            
            
              
            
            
        each.with_object({}) { |(key, value), diff| diff[key] = [value, nil] }
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def fetch_deep(*keys, default: NilClass, &)
           
        
      
        
          
- 
            
              10
            
            
              
            
            
        keys.reduce fallback(keys.shift, default, &) do |value, key|
           
        
      
        
          
- 
            
              13
            
            
              
                
                  else: 12
                
              
                
                  then: 1
                
              
            
            
          unless value.is_a?(::Hash) || (value.is_a?(::Array) && key.is_a?(::Integer))
           
        
      
        
          
- 
            
              1
            
            
              
            
            
            fail KeyError, "Unable to find #{key.inspect} in #{value.inspect}."
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              12
            
            
              
                
                  then: 11
                
              
                
                  else: 1
                
              
            
            
          default == NilClass ? value.fetch(key, &) : value.fetch(key, default)
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def fetch_value(key, *default, &)
           
        
      
        
          
- 
            
              6
            
            
              
                
                  then: 1
                
              
                
                  else: 1
                
              
            
            
        fetch(key, *default, &) || (yield if block_given?) || default.first
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def flatten_keys prefix: nil, delimiter: "_"
           
        
      
        
          
- 
            
              28
            
            
              
            
            
        reduce({}) do |accumulator, (key, value)|
           
        
      
        
          
- 
            
              38
            
            
              
                
                  then: 18
                
              
                
                  else: 20
                
              
            
            
          flat_key = prefix ? :"#{prefix}#{delimiter}#{key}" : key
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              38
            
            
              
                
                  else: 14
                
              
                
                  then: 24
                
              
            
            
          next accumulator.merge flat_key => value unless value.is_a? ::Hash
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              28
            
            
              
            
            
          accumulator.merge(recurse { value.flatten_keys prefix: flat_key, delimiter: })
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def flatten_keys!(prefix: nil, delimiter: "_") = replace flatten_keys(prefix:, delimiter:)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def recurse &block
           
        
      
        
          
- 
            
              29
            
            
              
                
                  else: 28
                
              
                
                  then: 1
                
              
            
            
        return self unless block
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              28
            
            
              
            
            
        transform = yield self
           
        
      
        
          
- 
            
              61
            
            
              
                
                  then: 4
                
              
                
                  else: 29
                
              
            
            
        transform.each { |key, value| transform[key] = value.recurse(&block) if value.is_a? ::Hash }
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def stringify_keys = transform_keys(&:to_s)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def stringify_keys! = transform_keys!(&:to_s)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def symbolize_keys = transform_keys(&:to_sym)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def symbolize_keys! = transform_keys!(&:to_sym)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def transform_value(key, &) = dup.transform_value!(key, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def transform_value! key
           
        
      
        
          
- 
            
              10
            
            
              
                
                  then: 6
                
              
                
                  else: 4
                
              
            
            
        block_given? && key?(key) ? merge!(key => yield(self[key])) : self
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def transform_with(**) = dup.transform_with!(**)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def transform_with!(**operations)
           
        
      
        
          
- 
            
              14
            
            
              
                
                  then: 6
                
              
                
                  else: 2
                
              
            
            
        operations.each { |key, function| self[key] = function.call self[key] if key? key }
           
        
      
        
          
- 
            
              6
            
            
              
            
            
        self
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def use &block
           
        
      
        
          
- 
            
              3
            
            
              
                
                  else: 2
                
              
                
                  then: 1
                
              
            
            
        return [] unless block
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              2
            
            
              
            
            
        block.parameters
           
        
      
        
          
- 
            
              4
            
            
              
            
            
             .map { |(_type, key)| self[key] || self[key.to_s] }
           
        
      
        
          
- 
            
              2
            
            
              
            
            
             .then { |values| yield values }
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def differences_from other
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        result = merge(other.to_h) { |_, one, two| [one, two].uniq }
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        result.select { |_, diff| diff.size == 2 }
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def fallback(key, default, &)
           
        
      
        
          
- 
            
              10
            
            
              
                
                  then: 8
                
              
                
                  else: 2
                
              
            
            
        default == NilClass ? fetch(key, &) : fetch(key, default)
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end