jannishuebl/orchparty

View on GitHub
lib/deep_merge.rb

Summary

Maintainability
A
45 mins
Test Coverage
module Hashie
  module Extensions
    module DeepMergeConcat

      def transform_values
        result = self.class.new
        each do |key, value|
          result[key] = yield(value)
        end
        result
      end

      def transform_values!
        each do |key, value|
          self[key] = yield(value)
        end
      end

      def transform_keys
        result = self.class.new
        each_key do |key|
          result[yield(key)] = self[key]
        end
        result
      end

      def transform_keys!
        keys.each do |key|
          self[yield(key)] = delete(key)
        end
        self
      end

      def deep_sort_by_key_and_sort_array(exclusions = [], &block)
        self.keys.sort(&block).reduce({}) do |seed, key|
          seed[key] = self[key]
          unless exclusions.include?(key.to_s)
            if seed[key].is_a?(Hash)
              seed[key] = seed[key].deep_sort_by_key_and_sort_array(exclusions, &block)
            elsif seed[key].is_a?(Hashie::Array)
              seed[key] = seed[key].sort(&block)
            end
          end
          seed
        end
      end

      # Returns a new hash with +self+ and +other_hash+ merged recursively.
      def deep_sort(&block)
        copy = dup
        copy.extend(Hashie::Extensions::DeepMergeConcat) unless copy.respond_to?(:deep_sort!)
        copy.deep_sort!(&block)
      end

      # Returns a new hash with +self+ and +other_hash+ merged recursively.
      # Modifies the receiver in place.
      def deep_sort!(&block)
        _recursive_sort(self, &block)
        self
      end

      # Returns a new hash with +self+ and +other_hash+ merged recursively.
      def deep_merge_concat(other_hash, &block)
        copy = dup
        copy.extend(Hashie::Extensions::DeepMergeConcat) unless copy.respond_to?(:deep_merge_concat!)
        copy.deep_merge_concat!(other_hash, &block)
      end

      # Returns a new hash with +self+ and +other_hash+ merged recursively.
      # Modifies the receiver in place.
      def deep_merge_concat!(other_hash, &block)
        return self unless other_hash.is_a?(::Hash)
        _recursive_merge_concat(self, other_hash, &block)
        self
      end

      def deep_transform_values(&block)
        _deep_transform_values_in_object(self, &block)
      end

      def deep_transform_values!(&block)
        _deep_transform_values_in_object!(self, &block)
      end

      private

      def _deep_transform_values_in_object(object, &block)
        case object
        when Hash
          object.each_with_object({}) do |arg, result|
            key = arg.first
            value = arg.last
            result[key] = _deep_transform_values_in_object(value, &block)
          end
        when Array
          object.map {|e| _deep_transform_values_in_object(e, &block) }
        else
          yield(object)
        end
      end

      def _deep_transform_values_in_object!(object, &block)
        case object
        when Hash
          object.each do |key, value|
            object[key] = _deep_transform_values_in_object!(value, &block)
          end
        when Array
          object.map! {|e| _deep_transform_values_in_object!(e, &block) }
        else
          yield(object)
        end
      end

      def _recursive_sort(object, &block)
        case object
        when Hash
          object = Orchparty::AST::Node.new(object.sort {|a, b| block.call(a[0], b[0]) }.to_h)
          object.each do |key, value|
            object[key] = _recursive_sort(value, &block)
          end
          object
        when Array
          object.map! {|e| _recursive_sort(e, &block) }.sort(&block)
        else
          yield(object)
        end
      end


      def _recursive_merge_concat(hash, other_hash, &block)
        other_hash.each do |k, v|
          hash[k] = if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
                      _recursive_merge(hash[k], v, &block)
                    elsif hash.key?(k) && hash[k].is_a?(::Array) && v.is_a?(::Array)
                      hash[k].concat(v).uniq
                    else
                      if hash.key?(k) && block_given?
                        block.call(k, hash[k], v)
                      else
                        v.respond_to?(:deep_dup) ? v.deep_dup : v
                      end
                    end
        end
        hash
      end
    end
  end
end