3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/json-diff/diff.rb', line 3
def self.diff(before, after, opts = {})
path = opts[:path] || '/'
include_addition = (opts[:additions] == nil) ? true : opts[:additions]
include_moves = (opts[:moves] == nil) ? true : opts[:moves]
include_was = (opts[:include_was] == nil) ? false : opts[:include_was]
original_indices = (opts[:original_indices] == nil) ? false : opts[:original_indices]
changes = []
if before.is_a?(Hash)
if !after.is_a?(Hash)
changes << replace(path, include_was ? before : nil, after)
else
lost = before.keys - after.keys
lost.each do |key|
inner_path = extend_json_pointer(path, key)
changes << remove(inner_path, include_was ? before[key] : nil)
end
if include_addition
gained = after.keys - before.keys
gained.each do |key|
inner_path = extend_json_pointer(path, key)
changes << add(inner_path, after[key])
end
end
kept = before.keys & after.keys
kept.each do |key|
inner_path = extend_json_pointer(path, key)
changes += diff(before[key], after[key], opts.merge(path: inner_path))
end
end
elsif before.is_a?(Array)
if !after.is_a?(Array)
changes << replace(path, include_was ? before : nil, after)
elsif before.size == 0
if include_addition
after.each_with_index do |item, index|
inner_path = extend_json_pointer(path, index)
changes << add(inner_path, item)
end
end
elsif after.size == 0
before.each do |item|
inner_path = extend_json_pointer(path, 0)
changes << remove(inner_path, include_was ? item : nil)
end
else
pairing = array_pairing(before, after)
pairing[:pairs].select! do |pair|
sim = pair[2]
kept = (sim >= 0.5)
if !kept
pairing[:removed] << pair[0]
pairing[:added] << pair[1]
end
kept
end
pairing[:pairs].each do |pair|
before_index, after_index = pair
inner_path = extend_json_pointer(path, before_index)
changes += diff(before[before_index], after[after_index], opts.merge(path: inner_path))
end
if !original_indices
pairing = array_changes(pairing)
end
pairing[:removed].each do |before_index|
inner_path = extend_json_pointer(path, before_index)
changes << remove(inner_path, include_was ? before[before_index] : nil)
end
pairing[:pairs].each do |pair|
before_index, after_index = pair
inner_before_path = extend_json_pointer(path, before_index)
inner_after_path = extend_json_pointer(path, after_index)
if before_index != after_index && include_moves
changes << move(inner_before_path, inner_after_path)
end
end
if include_addition
pairing[:added].each do |after_index|
inner_path = extend_json_pointer(path, after_index)
changes << add(inner_path, after[after_index])
end
end
end
else
if before != after
changes << replace(path, include_was ? before : nil, after)
end
end
changes
end
|