ManageIQ/manageiq

View on GitHub
lib/vmdb/settings/hash_differ.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# Inspired by http://stackoverflow.com/questions/1766741/comparing-ruby-hashes/7178108#7178108

module Vmdb
  class Settings
    class HashDiffer
      class MissingKey; end

      def self.changes(h1, h2)
        diff_to_deltas(diff(h1, h2))
      end

      def self.diff(h1, h2)
        keys = (h1.keys + h2.keys).uniq
        keys.each_with_object({}) do |k, result|
          v1 = h1.fetch(k, MissingKey)
          v2 = h2.fetch(k, MissingKey)
          next if v1 == v2

          child =
            if v1.kind_of?(Hash) && v2.kind_of?(Hash)
              diff(v1, v2)
            else
              v2
            end

          result[k] = child if child != MissingKey
        end
      end

      def self.diff_to_deltas(diff, key_path = "")
        diff.flat_map do |k, v|
          new_key_path = [key_path, k].join("/")
          case v
          when Hash
            diff_to_deltas(v, new_key_path)
          else
            {:key => new_key_path, :value => v}
          end
        end.compact
      end
    end
  end
end