From c18887d648fffa9520719d13d320100eee9ab0b3 Mon Sep 17 00:00:00 2001 From: Peizong Guo Date: Mon, 22 Feb 2016 11:24:23 -0500 Subject: [PATCH 1/3] Allow parsing matching_key to compare array element When elements in two array match by the matching_key, it will be treated as update Compatible with previous arguments --- lib/json-compare.rb | 8 +++- lib/json-compare/comparer.rb | 42 ++++++++++-------- spec/lib/json-compare_spec.rb | 81 ++++++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 20 deletions(-) diff --git a/lib/json-compare.rb b/lib/json-compare.rb index bdb41f6..10abf24 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..d936dc5 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 From 9e5cfcb4a3ee236ceb5e06214ac3cbef1504d4fc Mon Sep 17 00:00:00 2001 From: Peizong Guo Date: Mon, 22 Feb 2016 11:37:10 -0500 Subject: [PATCH 2/3] Update README.md Add document for array comparison with matching key --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 From a0cc9bd0a6694054e310559ce7e97b557bbc6e9c Mon Sep 17 00:00:00 2001 From: Peizong Guo Date: Mon, 22 Feb 2016 12:33:48 -0500 Subject: [PATCH 3/3] Change Hash format to compatible with ruby 1.8.7 --- lib/json-compare.rb | 2 +- spec/lib/json-compare_spec.rb | 38 +++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/json-compare.rb b/lib/json-compare.rb index 10abf24..8712f9a 100644 --- a/lib/json-compare.rb +++ b/lib/json-compare.rb @@ -4,7 +4,7 @@ module JsonCompare def self.get_diff(old, new, options = {}) if options.kind_of?(Array) - options = {excluded_keys: options} + options = {:excluded_keys => options} end comparer = JsonCompare::Comparer.new comparer.excluded_keys = options.delete(:excluded_keys) || [] diff --git a/spec/lib/json-compare_spec.rb b/spec/lib/json-compare_spec.rb index d936dc5..97daff0 100644 --- a/spec/lib/json-compare_spec.rb +++ b/spec/lib/json-compare_spec.rb @@ -136,57 +136,57 @@ describe 'Arrays Comparison with matching condition' do it "should treat as update" do - old = [{id: '123'}] - new = [{id: '456'}] + old = [{:id => '123'}] + new = [{:id => '456'}] result = JsonCompare.get_diff(old, new, {}) result.should eq({ :update => { - 0 => {:update => {id: '456'}} + 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}) + old = [{:id => '123'}] + new = [{:id => '456'}] + result = JsonCompare.get_diff(old, new, {:matching_key => :id}) result.should eq({ :remove => { - 0 => {id: '123'} + 0 => {:id => '123'} }, :append => { - 0 => {id: '456'} + 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}) + 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 => {:internal => true} } }, :append => { - 0 => {id: '456'}, - 2 => {id: '789'} + 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}) + 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'} + 0 => {:id => '456'} }, :remove => { - 1 => {id: '456'} + 1 => {:id => '456'} } }) end