Edit:
I keep coming back to this code to use it in projects I'm in. Here's the latest which is useful for deeply nested structures and based on Pete's code above. I usually drop it in config/initializers/core_ext.rb (in a Rails project):
class Hash
def deep_diff(other)
(self.keys + other.keys).uniq.inject({}) do |memo, key|
left = self[key]
right = other[key]
next memo if left == right
if left.respond_to?(:deep_diff) && right.respond_to?(:deep_diff)
memo[key] = left.deep_diff(right)
else
memo[key] = [left, right]
end
memo
end
end
end
class Array
def deep_diff(array)
largest = [self.count, array.count].max
memo = {}
0.upto(largest - 1) do |index|
left = self[index]
right = array[index]
next if left == right
if left.respond_to?(:deep_diff) && right.respond_to?(:deep_diff)
memo[index] = left.deep_diff(right)
else
memo[index] = [left, right]
end
end
memo
end
end
Here's a small demo:
> {a: [{b: "c", d: "e"}, {b: "c", f: "g"}]}.deep_diff({a: [{b: "c", d: "e"}, {b: "d", f: "g"}]})
=> {:a=>{1=>{:b=>["c", "d"]}}}
Older response:
I have found Rails' Hash diff method to not actually tell me what was on the left side and right side (which is far more useful). There was a plugin call "Riff", that has since disappeared, which would let you diff two ActiveRecord objects. Essentially:
class Hash
def diff(other)
self.keys.inject({}) do |memo, key|
unless self[key] == other[key]
memo[key] = [self[key], other[key]]
end
memo
end
end
end