diff --git a/README.md b/README.md index 89eb14c..a71be77 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,16 @@ If you want to exclude some keys from comparison use exclusion param: exclusion = ["from_user", "to_user_id"] result = JsonCompare.get_diff(old, new, exclusion) +Alternative way for excluding keys from comparison: + + exclusions = ["from_user", "to_user_id"] + result = JsonCompare.get_diff(old, new, excluded_key: excluded_keys) + +If you want to match array elements by a certain key: + + result = JsonCompare.get_diff(old, new, matching_key: "id") + + ## Contributing 1. Fork it diff --git a/lib/json-compare.rb b/lib/json-compare.rb index bdb41f6..8712f9a 100644 --- a/lib/json-compare.rb +++ b/lib/json-compare.rb @@ -2,9 +2,13 @@ require 'json-compare/comparer' module JsonCompare - def self.get_diff(old, new, exclusion = []) + def self.get_diff(old, new, options = {}) + if options.kind_of?(Array) + options = {:excluded_keys => options} + end comparer = JsonCompare::Comparer.new - comparer.excluded_keys = exclusion + comparer.excluded_keys = options.delete(:excluded_keys) || [] + comparer.matching_key = options.delete(:matching_key) comparer.compare_elements(old,new) end end diff --git a/lib/json-compare/comparer.rb b/lib/json-compare/comparer.rb index d2b3c71..cebec3e 100644 --- a/lib/json-compare/comparer.rb +++ b/lib/json-compare/comparer.rb @@ -1,7 +1,7 @@ module JsonCompare class Comparer - attr_accessor :excluded_keys + attr_accessor :excluded_keys, :matching_key def is_boolean(obj) !!obj == obj @@ -51,26 +51,34 @@ def compare_hashes(old_hash, new_hash) end def compare_arrays(old_array, new_array) - old_array_length = old_array.count + has_comparing_way = !matching_key.nil? + result = get_diffs_struct + new_array_index = 0 new_array_length = new_array.count - inters = [old_array.count, new_array.count].min - result = get_diffs_struct + old_array.each_with_index do |elem, index| + number = (new_array_index...new_array_length).detect do |n| + !( + has_comparing_way && + elem.kind_of?(Hash) && elem.has_key?(matching_key) && + new_array[n].kind_of?(Hash) && new_array[n].has_key?(matching_key) + ) || new_array[n][matching_key] == elem[matching_key] + end - (0..inters).map do |n| - res = compare_elements(old_array[n], new_array[n]) - result[:update][n] = res unless (res.nil? || (res.respond_to?(:empty?) && res.empty?)) + if number + res = compare_elements(elem, new_array[number]) + result[:update][index] = res unless (res.nil? || (res.respond_to?(:empty?) && res.empty?)) + (new_array_index...number).each do |n| + result[:append][n] = new_array[n] + end + new_array_index = number + 1 + else + result[:remove][index] = elem + end end - # the rest of the larger array - if inters == old_array_length - (inters..new_array_length).each do |n| - result[:append][n] = new_array[n] - end - else - (inters..old_array_length).each do |n| - result[:remove][n] = old_array[n] - end + (new_array_index...new_array_length).each do |n| + result[:append][n] = new_array[n] end filter_results(result) @@ -79,7 +87,7 @@ def compare_arrays(old_array, new_array) def compare_hash_array(old_hash, new_array) result = get_diffs_struct - (0..new_array.count).map do |n| + (0...new_array.count).map do |n| next if new_array[n].nil? if n == 0 res = compare_elements(old_hash, new_array[0]) diff --git a/spec/lib/json-compare_spec.rb b/spec/lib/json-compare_spec.rb index bfe373a..97daff0 100644 --- a/spec/lib/json-compare_spec.rb +++ b/spec/lib/json-compare_spec.rb @@ -129,7 +129,86 @@ it "should compare arrays of fixnums" do result = JsonCompare.get_diff([1, 2, 3], [1, 2, 3, 4]) - result.should eq(:append => { 3 => 4 }, :update => { 3 => 4 }) + result.should eq(:append => { 3 => 4 }) + end + end + + + describe 'Arrays Comparison with matching condition' do + it "should treat as update" do + old = [{:id => '123'}] + new = [{:id => '456'}] + result = JsonCompare.get_diff(old, new, {}) + result.should eq({ + :update => { + 0 => {:update => {:id => '456'}} + } + }) + end + + it "should treat as remove and append" do + old = [{:id => '123'}] + new = [{:id => '456'}] + result = JsonCompare.get_diff(old, new, {:matching_key => :id}) + result.should eq({ + :remove => { + 0 => {:id => '123'} + }, + :append => { + 0 => {:id => '456'} + } + }) + end + + it "should treat as remove and append" do + old = [{:id => '123'}] + new = [{:id => '456'}, {:id => '123', :internal => true}, {:id => '789'}] + result = JsonCompare.get_diff(old, new, {:matching_key => :id}) + result.should eq({ + :update => { + 0 => { + :append => {:internal => true} + } + }, + :append => { + 0 => {:id => '456'}, + 2 => {:id => '789'} + } + }) + end + + it "should follow the array's order when comparing" do + old = [{:id => '123'}, {:id => '456'}] + new = [{:id => '456'}, {:id => '123'}] + result = JsonCompare.get_diff(old, new, {:matching_key => :id}) + result.should eq({ + :append => { + 0 => {:id => '456'} + }, + :remove => { + 1 => {:id => '456'} + } + }) + end + end + + describe 'Hash Array Comparison' do + it "should return empty hash" do + old_hash = {"ID" => "123"} + new_array = [{"ID" => "123"}] + result = JsonCompare.get_diff(old_hash, new_array) + result.should eq({}) + end + + it "should consider new array elements as append" do + old_hash = {"ID" => "123"} + new_array = [{"ID" => "123"}, {"ID" => "456"}] + result = JsonCompare.get_diff(old_hash, new_array) + result.should eq({ + :append => { + 1 => {"ID" => "456"} + } + }) end end