hashdiff 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="