diff-lcs 1.2.5 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +6 -14
  2. data/.rspec +0 -1
  3. data/Code-of-Conduct.md +74 -0
  4. data/Contributing.md +118 -0
  5. data/History.md +319 -0
  6. data/{License.rdoc → License.md} +0 -0
  7. data/Manifest.txt +15 -8
  8. data/README.rdoc +18 -19
  9. data/Rakefile +57 -24
  10. data/autotest/discover.rb +3 -1
  11. data/bin/htmldiff +7 -4
  12. data/bin/ldiff +4 -1
  13. data/lib/diff-lcs.rb +1 -1
  14. data/lib/diff/lcs.rb +188 -254
  15. data/lib/diff/lcs/array.rb +1 -1
  16. data/lib/diff/lcs/backports.rb +9 -0
  17. data/lib/diff/lcs/block.rb +1 -1
  18. data/lib/diff/lcs/callbacks.rb +15 -12
  19. data/lib/diff/lcs/change.rb +33 -36
  20. data/lib/diff/lcs/htmldiff.rb +17 -16
  21. data/lib/diff/lcs/hunk.rb +156 -74
  22. data/lib/diff/lcs/internals.rb +43 -40
  23. data/lib/diff/lcs/ldiff.rb +51 -75
  24. data/lib/diff/lcs/string.rb +1 -1
  25. data/spec/change_spec.rb +31 -7
  26. data/spec/diff_spec.rb +24 -20
  27. data/spec/fixtures/aX +1 -0
  28. data/spec/fixtures/bXaX +1 -0
  29. data/spec/fixtures/ds1.csv +50 -0
  30. data/spec/fixtures/ds2.csv +51 -0
  31. data/spec/fixtures/ldiff/output.diff +4 -0
  32. data/spec/fixtures/ldiff/output.diff-c +7 -0
  33. data/spec/fixtures/ldiff/output.diff-e +3 -0
  34. data/spec/fixtures/ldiff/output.diff-f +3 -0
  35. data/spec/fixtures/ldiff/output.diff-u +5 -0
  36. data/spec/hunk_spec.rb +54 -43
  37. data/spec/issues_spec.rb +147 -17
  38. data/spec/lcs_spec.rb +24 -22
  39. data/spec/ldiff_spec.rb +87 -0
  40. data/spec/patch_spec.rb +182 -180
  41. data/spec/sdiff_spec.rb +91 -91
  42. data/spec/spec_helper.rb +143 -58
  43. data/spec/traverse_balanced_spec.rb +177 -177
  44. data/spec/traverse_sequences_spec.rb +63 -63
  45. metadata +87 -143
  46. checksums.yaml.gz.sig +0 -0
  47. data.tar.gz.sig +0 -3
  48. data/.autotest +0 -3
  49. data/.gemtest +0 -0
  50. data/.hoerc +0 -2
  51. data/.travis.yml +0 -22
  52. data/Contributing.rdoc +0 -64
  53. data/Gemfile +0 -20
  54. data/History.rdoc +0 -152
  55. metadata.gz.sig +0 -2
@@ -1,4 +1,4 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  class << Diff::LCS
4
4
  def diff_traversal(method, seq1, seq2, callbacks, &block)
@@ -45,8 +45,7 @@ class << Diff::LCS::Internals
45
45
  vector = []
46
46
 
47
47
  # Prune off any common elements at the beginning...
48
- while ((a_start <= a_finish) and (b_start <= b_finish) and
49
- (a[a_start] == b[b_start]))
48
+ while (a_start <= a_finish) and (b_start <= b_finish) and (a[a_start] == b[b_start])
50
49
  vector[a_start] = b_start
51
50
  a_start += 1
52
51
  b_start += 1
@@ -54,8 +53,7 @@ class << Diff::LCS::Internals
54
53
  b_start = a_start
55
54
 
56
55
  # Now the end...
57
- while ((a_start <= a_finish) and (b_start <= b_finish) and
58
- (a[a_finish] == b[b_finish]))
56
+ while (a_start <= a_finish) and (b_start <= b_finish) and (a[a_finish] == b[b_finish])
59
57
  vector[a_finish] = b_finish
60
58
  a_finish -= 1
61
59
  b_finish -= 1
@@ -68,7 +66,7 @@ class << Diff::LCS::Internals
68
66
  links = []
69
67
  string = a.kind_of?(String)
70
68
 
71
- (a_start .. a_finish).each do |i|
69
+ (a_start..a_finish).each do |i|
72
70
  ai = string ? a[i, 1] : a[i]
73
71
  bm = b_matches[ai]
74
72
  k = nil
@@ -78,13 +76,13 @@ class << Diff::LCS::Internals
78
76
  else
79
77
  k = replace_next_larger(thresh, j, k)
80
78
  end
81
- links[k] = [ (k > 0) ? links[k - 1] : nil, i, j ] unless k.nil?
79
+ links[k] = [k.positive? ? links[k - 1] : nil, i, j] unless k.nil?
82
80
  end
83
81
  end
84
82
 
85
83
  unless thresh.empty?
86
84
  link = links[thresh.size - 1]
87
- while not link.nil?
85
+ until link.nil?
88
86
  vector[link[1]] = link[2]
89
87
  link = link[0]
90
88
  end
@@ -93,14 +91,15 @@ class << Diff::LCS::Internals
93
91
  vector
94
92
  end
95
93
 
96
- # This method will analyze the provided patchset to provide a
97
- # single-pass normalization (conversion of the array form of
98
- # Diff::LCS::Change objects to the object form of same) and detection of
99
- # whether the patchset represents changes to be made.
94
+ # This method will analyze the provided patchset to provide a single-pass
95
+ # normalization (conversion of the array form of Diff::LCS::Change objects to
96
+ # the object form of same) and detection of whether the patchset represents
97
+ # changes to be made.
100
98
  def analyze_patchset(patchset, depth = 0)
101
- raise "Patchset too complex" if depth > 1
99
+ fail 'Patchset too complex' if depth > 1
102
100
 
103
101
  has_changes = false
102
+ new_patchset = []
104
103
 
105
104
  # Format:
106
105
  # [ # patchset
@@ -110,29 +109,28 @@ class << Diff::LCS::Internals
110
109
  # ]
111
110
  # ]
112
111
 
113
- patchset = patchset.map do |hunk|
112
+ patchset.each do |hunk|
114
113
  case hunk
115
114
  when Diff::LCS::Change
116
115
  has_changes ||= !hunk.unchanged?
117
- hunk
116
+ new_patchset << hunk
118
117
  when Array
119
- # Detect if the 'hunk' is actually an array-format
120
- # Change object.
118
+ # Detect if the 'hunk' is actually an array-format change object.
121
119
  if Diff::LCS::Change.valid_action? hunk[0]
122
120
  hunk = Diff::LCS::Change.from_a(hunk)
123
121
  has_changes ||= !hunk.unchanged?
124
- hunk
122
+ new_patchset << hunk
125
123
  else
126
124
  with_changes, hunk = analyze_patchset(hunk, depth + 1)
127
125
  has_changes ||= with_changes
128
- hunk.flatten
126
+ new_patchset.concat(hunk)
129
127
  end
130
128
  else
131
- raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}."
129
+ fail ArgumentError, "Cannot normalise a hunk of class #{hunk.class}."
132
130
  end
133
131
  end
134
132
 
135
- [ has_changes, patchset.flatten(1) ]
133
+ [has_changes, new_patchset]
136
134
  end
137
135
 
138
136
  # Examine the patchset and the source to see in which direction the
@@ -142,8 +140,6 @@ class << Diff::LCS::Internals
142
140
  # some time. This also works better with Diff::LCS::ContextChange or
143
141
  # Diff::LCS::Change as its source, as an array will cause the creation
144
142
  # of one of the above.
145
- #
146
- # Note: This will be deprecated as a public function in a future release.
147
143
  def intuit_diff_direction(src, patchset, limit = nil)
148
144
  string = src.kind_of?(String)
149
145
  count = left_match = left_miss = right_match = right_miss = 0
@@ -175,13 +171,11 @@ class << Diff::LCS::Internals
175
171
  when '!'
176
172
  if le == change.old_element
177
173
  left_match += 1
174
+ elsif re == change.new_element
175
+ right_match += 1
178
176
  else
179
- if re == change.new_element
180
- right_match += 1
181
- else
182
- left_miss += 1
183
- right_miss += 1
184
- end
177
+ left_miss += 1
178
+ right_miss += 1
185
179
  end
186
180
  end
187
181
  when Diff::LCS::Change
@@ -211,11 +205,11 @@ class << Diff::LCS::Internals
211
205
  end
212
206
  end
213
207
 
214
- break if (not limit.nil?) && (count > limit)
208
+ break if !limit.nil? && (count > limit)
215
209
  end
216
210
 
217
- no_left = (left_match == 0) && (left_miss > 0)
218
- no_right = (right_match == 0) && (right_miss > 0)
211
+ no_left = left_match.zero? && left_miss.positive?
212
+ no_right = right_match.zero? && right_miss.positive?
219
213
 
220
214
  case [no_left, no_right]
221
215
  when [false, true]
@@ -225,11 +219,20 @@ class << Diff::LCS::Internals
225
219
  else
226
220
  case left_match <=> right_match
227
221
  when 1
228
- :patch
222
+ if left_miss.zero?
223
+ :patch
224
+ else
225
+ :unpatch
226
+ end
229
227
  when -1
230
- :unpatch
228
+ if right_miss.zero?
229
+ :unpatch
230
+ else
231
+ :patch
232
+ end
231
233
  else
232
- raise "The provided patchset does not appear to apply to the provided value as either source or destination value."
234
+ fail "The provided patchset does not appear to apply to the provided \
235
+ enumerable as either source or destination value."
233
236
  end
234
237
  end
235
238
  end
@@ -252,14 +255,14 @@ class << Diff::LCS::Internals
252
255
  # Binary search for the insertion point
253
256
  last_index ||= enum.size
254
257
  first_index = 0
255
- while (first_index <= last_index)
258
+ while first_index <= last_index
256
259
  i = (first_index + last_index) >> 1
257
260
 
258
261
  found = enum[i]
259
262
 
260
- if value == found
261
- return nil
262
- elsif value > found
263
+ return nil if value == found
264
+
265
+ if value > found
263
266
  first_index = i + 1
264
267
  else
265
268
  last_index = i - 1
@@ -269,7 +272,7 @@ class << Diff::LCS::Internals
269
272
  # The insertion point is in first_index; overwrite the next larger
270
273
  # value.
271
274
  enum[first_index] = value
272
- return first_index
275
+ first_index
273
276
  end
274
277
  private :replace_next_larger
275
278
 
@@ -1,49 +1,21 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'diff/lcs/hunk'
6
6
 
7
- # == ldiff Usage
8
- # ldiff [options] oldfile newfile
9
- #
10
- # -c:: Displays a context diff with 3 lines of context.
11
- # -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines.
12
- # -u:: Displays a unified diff with 3 lines of context.
13
- # -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines.
14
- # -e:: Creates an 'ed' script to change oldfile to newfile.
15
- # -f:: Creates an 'ed' script to change oldfile to newfile in reverse order.
16
- # -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text.
17
- # --binary:: Treats the files as binary.
18
- # -q, --brief:: Reports only whether or not the files differ, not the details.
19
- # --help:: Shows the command-line help.
20
- # --version:: Shows the version of Diff::LCS.
21
- #
22
- # By default, runs produces an "old-style" diff, with output like UNIX diff.
23
- #
24
- # == Copyright
25
- # Copyright &copy; 2004 Austin Ziegler
26
- #
27
- # Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/>
28
- # Austin Ziegler <diff-lcs@halostatue.ca>
29
- #
30
- # This program is free software. It may be redistributed and/or modified under
31
- # the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
32
- # Ruby licence.
33
- module Diff::LCS::Ldiff
7
+ module Diff::LCS::Ldiff #:nodoc:
34
8
  BANNER = <<-COPYRIGHT
35
9
  ldiff #{Diff::LCS::VERSION}
36
- Copyright 2004-2013 Austin Ziegler
10
+ Copyright 2004-2019 Austin Ziegler
37
11
 
38
12
  Part of Diff::LCS.
39
- http://rubyforge.org/projects/ruwiki/
40
-
41
- Austin Ziegler <diff-lcs@halostatue.ca>
13
+ https://github.com/halostatue/diff-lcs
42
14
 
43
15
  This program is free software. It may be redistributed and/or modified under
44
16
  the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
45
17
  MIT licence.
46
- COPYRIGHT
18
+ COPYRIGHT
47
19
  end
48
20
 
49
21
  class << Diff::LCS::Ldiff
@@ -51,33 +23,42 @@ class << Diff::LCS::Ldiff
51
23
  attr_reader :file_old, :file_new #:nodoc:
52
24
  attr_reader :data_old, :data_new #:nodoc:
53
25
 
54
- def run(args, input = $stdin, output = $stdout, error = $stderr) #:nodoc:
26
+ def run(args, _input = $stdin, output = $stdout, error = $stderr) #:nodoc:
55
27
  @binary = nil
56
28
 
57
29
  args.options do |o|
58
30
  o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile"
59
- o.separator ""
60
- o.on('-c', '-C', '--context [LINES]', Numeric, 'Displays a context diff with LINES lines', 'of context. Default 3 lines.') do |ctx|
31
+ o.separator ''
32
+ o.on(
33
+ '-c', '-C', '--context [LINES]', Integer,
34
+ 'Displays a context diff with LINES lines', 'of context. Default 3 lines.'
35
+ ) do |ctx|
61
36
  @format = :context
62
37
  @lines = ctx || 3
63
38
  end
64
- o.on('-u', '-U', '--unified [LINES]', Numeric, 'Displays a unified diff with LINES lines', 'of context. Default 3 lines.') do |ctx|
39
+ o.on(
40
+ '-u', '-U', '--unified [LINES]', Integer,
41
+ 'Displays a unified diff with LINES lines', 'of context. Default 3 lines.'
42
+ ) do |ctx|
65
43
  @format = :unified
66
44
  @lines = ctx || 3
67
45
  end
68
- o.on('-e', 'Creates an \'ed\' script to change', 'oldfile to newfile.') do |ctx|
46
+ o.on('-e', 'Creates an \'ed\' script to change', 'oldfile to newfile.') do |_ctx|
69
47
  @format = :ed
70
48
  end
71
- o.on('-f', 'Creates an \'ed\' script to change', 'oldfile to newfile in reverse order.') do |ctx|
49
+ o.on('-f', 'Creates an \'ed\' script to change', 'oldfile to newfile in reverse order.') do |_ctx|
72
50
  @format = :reverse_ed
73
51
  end
74
- o.on('-a', '--text', 'Treat the files as text and compare them', 'line-by-line, even if they do not seem', 'to be text.') do |txt|
52
+ o.on(
53
+ '-a', '--text',
54
+ 'Treat the files as text and compare them', 'line-by-line, even if they do not seem', 'to be text.'
55
+ ) do |_txt|
75
56
  @binary = false
76
57
  end
77
- o.on('--binary', 'Treats the files as binary.') do |bin|
58
+ o.on('--binary', 'Treats the files as binary.') do |_bin|
78
59
  @binary = true
79
60
  end
80
- o.on('-q', '--brief', 'Report only whether or not the files', 'differ, not the details.') do |ctx|
61
+ o.on('-q', '--brief', 'Report only whether or not the files', 'differ, not the details.') do |_ctx|
81
62
  @format = :report
82
63
  end
83
64
  o.on_tail('--help', 'Shows this text.') do
@@ -85,10 +66,10 @@ class << Diff::LCS::Ldiff
85
66
  return 0
86
67
  end
87
68
  o.on_tail('--version', 'Shows the version of Diff::LCS.') do
88
- error << BANNER
69
+ error << Diff::LCS::Ldiff::BANNER
89
70
  return 0
90
71
  end
91
- o.on_tail ""
72
+ o.on_tail ''
92
73
  o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.'
93
74
  o.parse!
94
75
  end
@@ -117,25 +98,19 @@ class << Diff::LCS::Ldiff
117
98
  # items we've read from each file will differ by FLD (could be 0).
118
99
  file_length_difference = 0
119
100
 
120
- if @binary.nil? or @binary
121
- data_old = IO::read(file_old)
122
- data_new = IO::read(file_new)
101
+ data_old = IO.read(file_old)
102
+ data_new = IO.read(file_new)
123
103
 
124
- # Test binary status
125
- if @binary.nil?
126
- old_txt = data_old[0...4096].scan(/\0/).empty?
127
- new_txt = data_new[0...4096].scan(/\0/).empty?
128
- @binary = (not old_txt) or (not new_txt)
129
- old_txt = new_txt = nil
130
- end
104
+ # Test binary status
105
+ if @binary.nil?
106
+ old_txt = data_old[0, 4096].scan(/\0/).empty?
107
+ new_txt = data_new[0, 4096].scan(/\0/).empty?
108
+ @binary = !old_txt || !new_txt
109
+ end
131
110
 
132
- unless @binary
133
- data_old = data_old.split($/).map { |e| e.chomp }
134
- data_new = data_new.split($/).map { |e| e.chomp }
135
- end
136
- else
137
- data_old = IO::readlines(file_old).map { |e| e.chomp }
138
- data_new = IO::readlines(file_new).map { |e| e.chomp }
111
+ unless @binary
112
+ data_old = data_old.lines.to_a
113
+ data_new = data_new.lines.to_a
139
114
  end
140
115
 
141
116
  # diff yields lots of pieces, each of which is basically a Block object
@@ -154,10 +129,10 @@ class << Diff::LCS::Ldiff
154
129
  end
155
130
 
156
131
  if (@format == :unified) or (@format == :context)
157
- ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
158
- puts "#{char_old} #{file_old}\t#{ft}"
159
- ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
160
- puts "#{char_new} #{file_new}\t#{ft}"
132
+ ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')
133
+ output << "#{char_old} #{file_old}\t#{ft}\n"
134
+ ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')
135
+ output << "#{char_new} #{file_new}\t#{ft}\n"
161
136
  end
162
137
 
163
138
  # Loop over hunks. If a hunk overlaps with the last hunk, join them.
@@ -170,26 +145,27 @@ class << Diff::LCS::Ldiff
170
145
  end
171
146
 
172
147
  diffs.each do |piece|
173
- begin
174
- hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines,
175
- file_length_difference)
148
+ begin # rubocop:disable Style/RedundantBegin
149
+ hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, file_length_difference)
176
150
  file_length_difference = hunk.file_length_difference
177
151
 
178
152
  next unless oldhunk
179
- next if (@lines > 0) and hunk.merge(oldhunk)
153
+ next if @lines.positive? and hunk.merge(oldhunk)
180
154
 
181
- output << oldhunk.diff(@format) << "\n"
155
+ output << oldhunk.diff(@format)
156
+ output << "\n" if @format == :unified
182
157
  ensure
183
158
  oldhunk = hunk
184
159
  end
185
160
  end
186
161
 
187
- output << oldhunk.diff(@format) << "\n"
162
+ last = oldhunk.diff(@format, true)
163
+ last << "\n" if last.respond_to?(:end_with?) && !last.end_with?("\n")
188
164
 
189
- if @format == :ed
190
- output.reverse_each { |e| real_output << e.diff(:ed_finish) }
191
- end
165
+ output << last
166
+
167
+ output.reverse_each { |e| real_output << e.diff(:ed_finish) } if @format == :ed
192
168
 
193
- return 1
169
+ 1
194
170
  end
195
171
  end
@@ -1,4 +1,4 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  class String
4
4
  include Diff::LCS
@@ -1,9 +1,9 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Diff::LCS::Change do
6
- describe "an add" do
6
+ describe 'an add' do
7
7
  subject { described_class.new('+', 0, 'element') }
8
8
  it { should_not be_deleting }
9
9
  it { should be_adding }
@@ -13,7 +13,7 @@ describe Diff::LCS::Change do
13
13
  it { should_not be_finished_b }
14
14
  end
15
15
 
16
- describe "a delete" do
16
+ describe 'a delete' do
17
17
  subject { described_class.new('-', 0, 'element') }
18
18
  it { should be_deleting }
19
19
  it { should_not be_adding }
@@ -23,7 +23,7 @@ describe Diff::LCS::Change do
23
23
  it { should_not be_finished_b }
24
24
  end
25
25
 
26
- describe "an unchanged" do
26
+ describe 'an unchanged' do
27
27
  subject { described_class.new('=', 0, 'element') }
28
28
  it { should_not be_deleting }
29
29
  it { should_not be_adding }
@@ -33,7 +33,7 @@ describe Diff::LCS::Change do
33
33
  it { should_not be_finished_b }
34
34
  end
35
35
 
36
- describe "a changed" do
36
+ describe 'a changed' do
37
37
  subject { described_class.new('!', 0, 'element') }
38
38
  it { should_not be_deleting }
39
39
  it { should_not be_adding }
@@ -43,7 +43,7 @@ describe Diff::LCS::Change do
43
43
  it { should_not be_finished_b }
44
44
  end
45
45
 
46
- describe "a finished_a" do
46
+ describe 'a finished_a' do
47
47
  subject { described_class.new('>', 0, 'element') }
48
48
  it { should_not be_deleting }
49
49
  it { should_not be_adding }
@@ -53,7 +53,7 @@ describe Diff::LCS::Change do
53
53
  it { should_not be_finished_b }
54
54
  end
55
55
 
56
- describe "a finished_b" do
56
+ describe 'a finished_b' do
57
57
  subject { described_class.new('<', 0, 'element') }
58
58
  it { should_not be_deleting }
59
59
  it { should_not be_adding }
@@ -62,4 +62,28 @@ describe Diff::LCS::Change do
62
62
  it { should_not be_finished_a }
63
63
  it { should be_finished_b }
64
64
  end
65
+
66
+ describe 'as array' do
67
+ it 'should be converted' do
68
+ action, position, element = described_class.new('!', 0, 'element')
69
+ expect(action).to eq '!'
70
+ expect(position).to eq 0
71
+ expect(element).to eq 'element'
72
+ end
73
+ end
74
+ end
75
+
76
+ describe Diff::LCS::ContextChange do
77
+ describe 'as array' do
78
+ it 'should be converted' do
79
+ action, (old_position, old_element), (new_position, new_element) =
80
+ described_class.new('!', 1, 'old_element', 2, 'new_element')
81
+
82
+ expect(action).to eq '!'
83
+ expect(old_position).to eq 1
84
+ expect(old_element).to eq 'old_element'
85
+ expect(new_position).to eq 2
86
+ expect(new_element).to eq 'new_element'
87
+ end
88
+ end
65
89
  end