hashdiff 0.3.8 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 482b0233e91f747074eada75539247148a14d31d
4
- data.tar.gz: 0aba247c54a9e96d433d77ecc76b3e4cf1396075
3
+ metadata.gz: 1de380f239260b12890d36de1548ee8a9159a15d
4
+ data.tar.gz: be13f7000b31ac211e59c8e5c924a976a39fb26c
5
5
  SHA512:
6
- metadata.gz: 10fe5b5b37c1a80d317d509b133a880211723ff4b184e892678eb7211de5bcf41b27d482151237052efabd6c9eee336507d5df4f19e2b0e727de970e47280cb4
7
- data.tar.gz: 22baf87f78115a872a6df5600b8a31c2d8e3c35991ca114aff60a89af70d29b530f3771386d8bb67578324884f30291e120ed418f78c2768baa746e456f65d71
6
+ metadata.gz: bad33e3fd08a4f7b14388f54c17060153a48832eda6c06e6d137ce23b901cd14183630eabcfa7e1da6d2c93f33d7b59109a7fee0e78a23f2a3102e3576c35846
7
+ data.tar.gz: 7fa406149636c91d9cc5abc49b926f92e8b4962654e9b78ef18b3938dc971ce2f51cf16b2c01b3968556cc20fbfb577437b76a7094ecf0ba4eb5cd00cdba0bb3
@@ -17,5 +17,8 @@ Metrics/ModuleLength:
17
17
  Enabled: false
18
18
  Style/Documentation:
19
19
  Enabled: false
20
+ Style/FrozenStringLiteralComment:
21
+ Enabled: true
22
+ EnforcedStyle: always
20
23
  RSpec/ExampleLength:
21
24
  Enabled: false
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'http://rubygems.org'
2
4
  gemspec
3
5
 
data/README.md CHANGED
@@ -8,6 +8,9 @@ HashDiff does not monkey-patch any existing class. All features are contained in
8
8
 
9
9
  **Docs**: [Documentation](http://rubydoc.info/gems/hashdiff)
10
10
 
11
+
12
+ __WARNING__: Don't use the library for comparing large arrays, say ~10K (see #49).
13
+
11
14
  ## Why HashDiff?
12
15
 
13
16
  Given two Hashes A and B, sometimes you face the question: what's the smallest modification that can be made to change A into B?
@@ -262,4 +265,3 @@ HashDiff.diff(a, b) => []
262
265
  ## License
263
266
 
264
267
  HashDiff is distributed under the MIT-LICENSE.
265
-
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH.push File.expand_path('lib', __dir__)
2
4
 
3
5
  require 'rubocop/rake_task'
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## v0.3.9 2019-04-22
4
+
5
+ * Performance tweak (thanks @krzysiek1507: #51 #52 #53)
6
+
3
7
  ## v0.3.8 2018-12-30
4
8
 
5
9
  * Add Rubocop and drops Ruby 1.9 support #47
@@ -73,4 +77,3 @@ For example, `diff({a:2, c:[4, 5]}, {a:2}) will generate following output:
73
77
  instead of following:
74
78
 
75
79
  [['-', 'c[0]', 4], ['-', 'c[1]', 5], ['-', 'c', []]]
76
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH << File.expand_path('lib', __dir__)
2
4
  require 'hashdiff/version'
3
5
 
@@ -12,7 +14,7 @@ Gem::Specification.new do |s|
12
14
  s.test_files = `git ls-files -- Appraisals {spec}/*`.split("\n")
13
15
 
14
16
  s.require_paths = ['lib']
15
- s.required_ruby_version = Gem::Requirement.new('>= 1.9.3')
17
+ s.required_ruby_version = Gem::Requirement.new('>= 2.0.0')
16
18
 
17
19
  s.authors = ['Liu Fengyun']
18
20
  s.email = ['liufengyunchina@gmail.com']
@@ -1,6 +1,8 @@
1
- require 'hashdiff/util'
2
- require 'hashdiff/lcs'
3
- require 'hashdiff/linear_compare_array'
4
- require 'hashdiff/diff'
5
- require 'hashdiff/patch'
6
- require 'hashdiff/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hashdiff/util'
4
+ require_relative 'hashdiff/lcs'
5
+ require_relative 'hashdiff/linear_compare_array'
6
+ require_relative 'hashdiff/diff'
7
+ require_relative 'hashdiff/patch'
8
+ require_relative 'hashdiff/version'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDiff
2
4
  # Best diff two objects, which tries to generate the smallest change set using different similarity values.
3
5
  #
@@ -120,13 +122,15 @@ module HashDiff
120
122
  elsif obj1.is_a?(Array) && !opts[:use_lcs]
121
123
  result.concat(LinearCompareArray.call(obj1, obj2, opts))
122
124
  elsif obj1.is_a?(Hash)
125
+ obj1_keys = obj1.keys
126
+ obj2_keys = obj2.keys
123
127
 
124
- deleted_keys = obj1.keys - obj2.keys
125
- common_keys = obj1.keys & obj2.keys
126
- added_keys = obj2.keys - obj1.keys
128
+ deleted_keys = (obj1_keys - obj2_keys).sort_by(&:to_s)
129
+ common_keys = (obj1_keys & obj2_keys).sort_by(&:to_s)
130
+ added_keys = (obj2_keys - obj1_keys).sort_by(&:to_s)
127
131
 
128
132
  # add deleted properties
129
- deleted_keys.sort_by { |k, _v| k.to_s }.each do |k|
133
+ deleted_keys.each do |k|
130
134
  change_key = prefix_append_key(opts[:prefix], k, opts)
131
135
  custom_result = custom_compare(opts[:comparison], change_key, obj1[k], nil)
132
136
 
@@ -138,13 +142,13 @@ module HashDiff
138
142
  end
139
143
 
140
144
  # recursive comparison for common keys
141
- common_keys.sort_by { |k, _v| k.to_s }.each do |k|
145
+ common_keys.each do |k|
142
146
  prefix = prefix_append_key(opts[:prefix], k, opts)
143
147
  result.concat(diff(obj1[k], obj2[k], opts.merge(prefix: prefix)))
144
148
  end
145
149
 
146
150
  # added properties
147
- added_keys.sort_by { |k, _v| k.to_s }.each do |k|
151
+ added_keys.each do |k|
148
152
  change_key = prefix_append_key(opts[:prefix], k, opts)
149
153
  next if obj1.key?(k)
150
154
 
@@ -169,28 +173,33 @@ module HashDiff
169
173
  #
170
174
  # diff array using LCS algorithm
171
175
  def self.diff_array_lcs(arraya, arrayb, options = {})
172
- opts = {
173
- prefix: '',
174
- similarity: 0.8,
175
- delimiter: '.'
176
- }.merge!(options)
176
+ return [] if arraya.empty? && arrayb.empty?
177
177
 
178
178
  change_set = []
179
- return [] if arraya.empty? && arrayb.empty?
180
179
 
181
180
  if arraya.empty?
182
181
  arrayb.each_index do |index|
183
182
  change_set << ['+', index, arrayb[index]]
184
183
  end
184
+
185
185
  return change_set
186
- elsif arrayb.empty?
186
+ end
187
+
188
+ if arrayb.empty?
187
189
  arraya.each_index do |index|
188
190
  i = arraya.size - index - 1
189
191
  change_set << ['-', i, arraya[i]]
190
192
  end
193
+
191
194
  return change_set
192
195
  end
193
196
 
197
+ opts = {
198
+ prefix: '',
199
+ similarity: 0.8,
200
+ delimiter: '.'
201
+ }.merge!(options)
202
+
194
203
  links = lcs(arraya, arrayb, opts)
195
204
 
196
205
  # yield common
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDiff
2
4
  # @private
3
5
  #
4
6
  # caculate array difference using LCS algorithm
5
7
  # http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
6
8
  def self.lcs(arraya, arrayb, options = {})
9
+ return [] if arraya.empty? || arrayb.empty?
10
+
7
11
  opts = { similarity: 0.8 }.merge!(options)
8
12
 
9
13
  opts[:prefix] = prefix_append_array_index(opts[:prefix], '*', opts)
10
14
 
11
- return [] if arraya.empty? || arrayb.empty?
12
-
13
15
  a_start = b_start = 0
14
16
  a_finish = arraya.size - 1
15
17
  b_finish = arrayb.size - 1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDiff
2
4
  # @private
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This module provides methods to diff two hash, patch and unpatch hash
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDiff
2
4
  # @private
3
5
  #
@@ -5,14 +7,15 @@ module HashDiff
5
7
  def self.similar?(obja, objb, options = {})
6
8
  return compare_values(obja, objb, options) unless obja.is_a?(Array) || obja.is_a?(Hash) || objb.is_a?(Array) || objb.is_a?(Hash)
7
9
 
8
- opts = { similarity: 0.8 }.merge(options)
9
-
10
10
  count_a = count_nodes(obja)
11
11
  count_b = count_nodes(objb)
12
- diffs = count_diff diff(obja, objb, opts)
13
12
 
14
13
  return true if (count_a + count_b).zero?
15
14
 
15
+ opts = { similarity: 0.8 }.merge!(options)
16
+
17
+ diffs = count_diff diff(obja, objb, opts)
18
+
16
19
  (1 - diffs.to_f / (count_a + count_b).to_f) >= opts[:similarity]
17
20
  end
18
21
 
@@ -81,8 +84,8 @@ module HashDiff
81
84
  #
82
85
  # check for equality or "closeness" within given tolerance
83
86
  def self.compare_values(obj1, obj2, options = {})
84
- if (options[:numeric_tolerance].is_a? Numeric) &&
85
- [obj1, obj2].all? { |v| v.is_a? Numeric }
87
+ if options[:numeric_tolerance].is_a?(Numeric) &&
88
+ obj1.is_a?(Numeric) && obj2.is_a?(Numeric)
86
89
  return (obj1 - obj2).abs <= options[:numeric_tolerance]
87
90
  end
88
91
 
@@ -103,9 +106,7 @@ module HashDiff
103
106
  #
104
107
  # check if objects are comparable
105
108
  def self.comparable?(obj1, obj2, strict = true)
106
- [Array, Hash].each do |type|
107
- return true if obj1.is_a?(type) && obj2.is_a?(type)
108
- end
109
+ return true if (obj1.is_a?(Array) || obj1.is_a?(Hash)) && obj2.is_a?(obj1.class)
109
110
  return true if !strict && obj1.is_a?(Numeric) && obj2.is_a?(Numeric)
110
111
 
111
112
  obj1.is_a?(obj2.class) && obj2.is_a?(obj1.class)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashDiff
2
- VERSION = '0.3.8'.freeze
4
+ VERSION = '0.3.9'.freeze
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff::LinearCompareArray do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe HashDiff do
@@ -18,6 +20,14 @@ describe HashDiff do
18
20
  described_class.similar?(a, b, similarity: 1).should be false
19
21
  end
20
22
 
23
+ it 'is able to tell similiar empty hash' do
24
+ described_class.similar?({}, {}, 1).should be true
25
+ end
26
+
27
+ it 'is able to tell similiar empty array' do
28
+ described_class.similar?([], [], 1).should be true
29
+ end
30
+
21
31
  it 'is able to tell similiar hash with values within tolerance' do
22
32
  a = { 'a' => 1.5, 'b' => 2.25, 'c' => 3, 'd' => 4, 'e' => 5 }
23
33
  b = { 'a' => 1.503, 'b' => 2.22, 'c' => 3, 'e' => 5 }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
4
 
3
5
  require 'rubygems'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashdiff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liu Fengyun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-30 00:00:00.000000000 Z
11
+ date: 2019-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bluecloth
@@ -126,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - ">="
128
128
  - !ruby/object:Gem::Version
129
- version: 1.9.3
129
+ version: 2.0.0
130
130
  required_rubygems_version: !ruby/object:Gem::Requirement
131
131
  requirements:
132
132
  - - ">="