Created
September 21, 2015 21:23
-
-
Save cantino/7c2251bb0a9721f67bcc to your computer and use it in GitHub Desktop.
Recursive Ruby data structure diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ObjectComparisonHelper | |
def deep_hash_diff(obj1, obj2, path = 'root', differences = []) | |
if obj1.class != obj2.class | |
differences << "object types differ at #{path}: #{obj1.class} vs #{obj2.class}" | |
else | |
case obj1 | |
when Hash, HashWithIndifferentAccess | |
differences << "key sets differ at #{path}: #{obj1.keys.inspect} vs #{obj2.keys.inspect}" if obj1.keys.to_set != obj2.keys.to_set | |
obj1.each do |key, value| | |
deep_hash_diff(value, obj2[key], "#{path}.#{key}", differences) | |
end | |
when Array | |
differences << "array lengths differ at #{path}: #{obj1.length} vs #{obj2.length}" if obj1.length != obj2.length | |
obj1.zip(obj2).each.with_index do |(item1, item2), index| | |
deep_hash_diff(item1, item2, "#{path}[#{index}]", differences) | |
end | |
else | |
differences << "values differ at #{path}: #{obj1} vs #{obj2}" if obj1 != obj2 | |
end | |
end | |
differences | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
describe ObjectComparisonHelpers do | |
let(:helper) do | |
Class.new { include ObjectComparisonHelpers }.new | |
end | |
describe '#deep_hash_diff' do | |
it 'outputs an array of difference information' do | |
obj1 = { | |
'key' => 'value', | |
:hash => { foo: :bar, counter: 1 }, | |
:type => Time.now, | |
:array => [1,2,3] | |
} | |
obj2 = { | |
'key' => 'value', | |
:hash => { foo: :bar, counter: 2 }, | |
:type => 'string', | |
:array => [1,2,3,4], | |
'spurious' => 'value' | |
} | |
helper.deep_hash_diff(obj1, obj2).should == [ | |
"key sets differ at root: [\"key\", :hash, :type, :array] vs [\"key\", :hash, :type, :array, \"spurious\"]", | |
"values differ at root.hash.counter: 1 vs 2", | |
"object types differ at root.type: Time vs String", | |
"array lengths differ at root.array: 3 vs 4" | |
] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment