Skip to content

Instantly share code, notes, and snippets.

@malkomalko
Forked from henrik/hash_deep_diff.rb
Created May 9, 2014 12:39
Show Gist options
  • Save malkomalko/0890e3b8add0d4d7dec6 to your computer and use it in GitHub Desktop.
Save malkomalko/0890e3b8add0d4d7dec6 to your computer and use it in GitHub Desktop.
# Recursively diff two hashes, showing only the differing values.
# By Henrik Nyh <http://henrik.nyh.se> 2009-07-14 under the MIT license.
#
# Example:
#
# a = {
# "same" => "same",
# "diff" => "a",
# "only a" => "a",
# "nest" => {
# "same" => "same",
# "diff" => "a"
# }
# }
#
# b = {
# "same" => "same",
# "diff" => "b",
# "only b" => "b",
# "nest" => {
# "same" => "same",
# "diff" => "b"
# }
# }
#
# a.deep_diff(b) # =>
#
# {
# "diff" => ["a", "b"],
# "only a" => ["a", nil],
# "only b" => [nil, "b"],
# "nest" => {
# "diff" => ["a", "b"]
# }
# }
#
#
# ActiveSupport's Hash#diff would give this for a.diff(b):
#
# {
# "diff" => "a",
# "only a" => "a",
# "only b" => "b",
# "nest" => {
# "same" => "same",
# "diff" => "a"
# }
# }
#
class Hash
def deep_diff(b)
a = self
(a.keys | b.keys).inject({}) do |diff, k|
if a[k] != b[k]
if a[k].respond_to?(:deep_diff) && b[k].respond_to?(:deep_diff)
diff[k] = a[k].deep_diff(b[k])
else
diff[k] = [a[k], b[k]]
end
end
diff
end
end
end
if __FILE__ == $0
require "test/unit"
class DeepDiffTest < Test::Unit::TestCase
def assert_deep_diff(diff, a, b)
assert_equal(diff, a.deep_diff(b))
end
def test_no_difference
assert_deep_diff(
{},
{"one" => 1, "two" => 2},
{"two" => 2, "one" => 1}
)
end
def test_fully_different
assert_deep_diff(
{"one" => [1, nil], "two" => [nil, 2]},
{"one" => 1},
{"two" => 2}
)
end
def test_simple_difference
assert_deep_diff(
{"one" => [1, "1"]},
{"one" => 1},
{"one" => "1"}
)
end
def test_complex_difference
assert_deep_diff(
{
"diff" => ["a", "b"],
"only a" => ["a", nil],
"only b" => [nil, "b"],
"nested" => {
"y" => {
"diff" => ["a", "b"]
}
}
},
{
"one" => "1",
"diff" => "a",
"only a" => "a",
"nested" => {
"x" => "x",
"y" => {
"a" => "a",
"diff" => "a"
}
}
},
{
"one" => "1",
"diff" => "b",
"only b" => "b",
"nested" => {
"x" => "x",
"y" => {
"a" => "a",
"diff" => "b"
}
}
}
)
end
def test_default_value
assert_deep_diff(
{"one" => [1, "default"]},
{"one" => 1},
Hash.new("default")
)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment