diff-lcs 1.2.3 → 1.4.1

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 +7 -0
  2. data/.rspec +0 -1
  3. data/Code-of-Conduct.md +74 -0
  4. data/Contributing.md +84 -0
  5. data/History.md +247 -0
  6. data/{License.rdoc → License.md} +0 -0
  7. data/Manifest.txt +15 -9
  8. data/README.rdoc +20 -24
  9. data/Rakefile +24 -23
  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 +181 -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 +2 -2
  18. data/lib/diff/lcs/callbacks.rb +15 -12
  19. data/lib/diff/lcs/change.rb +34 -37
  20. data/lib/diff/lcs/htmldiff.rb +17 -16
  21. data/lib/diff/lcs/hunk.rb +59 -47
  22. data/lib/diff/lcs/internals.rb +44 -40
  23. data/lib/diff/lcs/ldiff.rb +45 -65
  24. data/lib/diff/lcs/string.rb +1 -1
  25. data/spec/change_spec.rb +31 -7
  26. data/spec/diff_spec.rb +28 -18
  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 +37 -37
  37. data/spec/issues_spec.rb +60 -17
  38. data/spec/lcs_spec.rb +24 -22
  39. data/spec/ldiff_spec.rb +74 -0
  40. data/spec/patch_spec.rb +182 -180
  41. data/spec/sdiff_spec.rb +99 -87
  42. data/spec/spec_helper.rb +141 -58
  43. data/spec/traverse_balanced_spec.rb +177 -177
  44. data/spec/traverse_sequences_spec.rb +63 -63
  45. metadata +92 -188
  46. data.tar.gz.sig +0 -4
  47. data/.autotest +0 -3
  48. data/.gemtest +0 -0
  49. data/.hoerc +0 -2
  50. data/.travis.yml +0 -22
  51. data/Contributing.rdoc +0 -64
  52. data/Gemfile +0 -19
  53. data/History.rdoc +0 -135
  54. data/diff-lcs.gemspec +0 -63
  55. metadata.gz.sig +0 -0
@@ -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,16 +45,15 @@ 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
51
+ b_start += 1
52
52
  end
53
53
  b_start = a_start
54
54
 
55
55
  # Now the end...
56
- while ((a_start <= a_finish) and (b_start <= b_finish) and
57
- (a[a_finish] == b[b_finish]))
56
+ while (a_start <= a_finish) and (b_start <= b_finish) and (a[a_finish] == b[b_finish])
58
57
  vector[a_finish] = b_finish
59
58
  a_finish -= 1
60
59
  b_finish -= 1
@@ -67,7 +66,7 @@ class << Diff::LCS::Internals
67
66
  links = []
68
67
  string = a.kind_of?(String)
69
68
 
70
- (a_start .. a_finish).each do |i|
69
+ (a_start..a_finish).each do |i|
71
70
  ai = string ? a[i, 1] : a[i]
72
71
  bm = b_matches[ai]
73
72
  k = nil
@@ -77,13 +76,13 @@ class << Diff::LCS::Internals
77
76
  else
78
77
  k = replace_next_larger(thresh, j, k)
79
78
  end
80
- 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?
81
80
  end
82
81
  end
83
82
 
84
83
  unless thresh.empty?
85
84
  link = links[thresh.size - 1]
86
- while not link.nil?
85
+ until link.nil?
87
86
  vector[link[1]] = link[2]
88
87
  link = link[0]
89
88
  end
@@ -92,14 +91,15 @@ class << Diff::LCS::Internals
92
91
  vector
93
92
  end
94
93
 
95
- # This method will analyze the provided patchset to provide a
96
- # single-pass normalization (conversion of the array form of
97
- # Diff::LCS::Change objects to the object form of same) and detection of
98
- # 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.
99
98
  def analyze_patchset(patchset, depth = 0)
100
- raise "Patchset too complex" if depth > 1
99
+ fail 'Patchset too complex' if depth > 1
101
100
 
102
101
  has_changes = false
102
+ new_patchset = []
103
103
 
104
104
  # Format:
105
105
  # [ # patchset
@@ -109,29 +109,28 @@ class << Diff::LCS::Internals
109
109
  # ]
110
110
  # ]
111
111
 
112
- patchset = patchset.map do |hunk|
112
+ patchset.each do |hunk|
113
113
  case hunk
114
114
  when Diff::LCS::Change
115
115
  has_changes ||= !hunk.unchanged?
116
- hunk
116
+ new_patchset << hunk
117
117
  when Array
118
- # Detect if the 'hunk' is actually an array-format
119
- # Change object.
118
+ # Detect if the 'hunk' is actually an array-format change object.
120
119
  if Diff::LCS::Change.valid_action? hunk[0]
121
120
  hunk = Diff::LCS::Change.from_a(hunk)
122
121
  has_changes ||= !hunk.unchanged?
123
- hunk
122
+ new_patchset << hunk
124
123
  else
125
124
  with_changes, hunk = analyze_patchset(hunk, depth + 1)
126
125
  has_changes ||= with_changes
127
- hunk.flatten
126
+ new_patchset.concat(hunk)
128
127
  end
129
128
  else
130
- raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}."
129
+ fail ArgumentError, "Cannot normalise a hunk of class #{hunk.class}."
131
130
  end
132
131
  end
133
132
 
134
- [ has_changes, patchset.flatten(1) ]
133
+ [has_changes, new_patchset]
135
134
  end
136
135
 
137
136
  # Examine the patchset and the source to see in which direction the
@@ -141,8 +140,6 @@ class << Diff::LCS::Internals
141
140
  # some time. This also works better with Diff::LCS::ContextChange or
142
141
  # Diff::LCS::Change as its source, as an array will cause the creation
143
142
  # of one of the above.
144
- #
145
- # Note: This will be deprecated as a public function in a future release.
146
143
  def intuit_diff_direction(src, patchset, limit = nil)
147
144
  string = src.kind_of?(String)
148
145
  count = left_match = left_miss = right_match = right_miss = 0
@@ -174,13 +171,11 @@ class << Diff::LCS::Internals
174
171
  when '!'
175
172
  if le == change.old_element
176
173
  left_match += 1
174
+ elsif re == change.new_element
175
+ right_match += 1
177
176
  else
178
- if re == change.new_element
179
- right_match += 1
180
- else
181
- left_miss += 1
182
- right_miss += 1
183
- end
177
+ left_miss += 1
178
+ right_miss += 1
184
179
  end
185
180
  end
186
181
  when Diff::LCS::Change
@@ -210,11 +205,11 @@ class << Diff::LCS::Internals
210
205
  end
211
206
  end
212
207
 
213
- break if (not limit.nil?) && (count > limit)
208
+ break if !limit.nil? && (count > limit)
214
209
  end
215
210
 
216
- no_left = (left_match == 0) && (left_miss > 0)
217
- 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?
218
213
 
219
214
  case [no_left, no_right]
220
215
  when [false, true]
@@ -224,11 +219,20 @@ class << Diff::LCS::Internals
224
219
  else
225
220
  case left_match <=> right_match
226
221
  when 1
227
- :patch
222
+ if left_miss.zero?
223
+ :patch
224
+ else
225
+ :unpatch
226
+ end
228
227
  when -1
229
- :unpatch
228
+ if right_miss.zero?
229
+ :unpatch
230
+ else
231
+ :patch
232
+ end
230
233
  else
231
- 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."
232
236
  end
233
237
  end
234
238
  end
@@ -251,14 +255,14 @@ class << Diff::LCS::Internals
251
255
  # Binary search for the insertion point
252
256
  last_index ||= enum.size
253
257
  first_index = 0
254
- while (first_index <= last_index)
258
+ while first_index <= last_index
255
259
  i = (first_index + last_index) >> 1
256
260
 
257
261
  found = enum[i]
258
262
 
259
- if value == found
260
- return nil
261
- elsif value > found
263
+ return nil if value == found
264
+
265
+ if value > found
262
266
  first_index = i + 1
263
267
  else
264
268
  last_index = i - 1
@@ -268,7 +272,7 @@ class << Diff::LCS::Internals
268
272
  # The insertion point is in first_index; overwrite the next larger
269
273
  # value.
270
274
  enum[first_index] = value
271
- return first_index
275
+ first_index
272
276
  end
273
277
  private :replace_next_larger
274
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
@@ -118,15 +99,14 @@ class << Diff::LCS::Ldiff
118
99
  file_length_difference = 0
119
100
 
120
101
  if @binary.nil? or @binary
121
- data_old = IO::read(file_old)
122
- data_new = IO::read(file_new)
102
+ data_old = IO.read(file_old)
103
+ data_new = IO.read(file_new)
123
104
 
124
105
  # Test binary status
125
106
  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
107
+ old_txt = data_old[0, 4096].scan(/\0/).empty?
108
+ new_txt = data_new[0, 4096].scan(/\0/).empty?
109
+ @binary = !old_txt or !new_txt
130
110
  end
131
111
 
132
112
  unless @binary
@@ -134,8 +114,8 @@ class << Diff::LCS::Ldiff
134
114
  data_new = data_new.split($/).map { |e| e.chomp }
135
115
  end
136
116
  else
137
- data_old = IO::readlines(file_old).map { |e| e.chomp }
138
- data_new = IO::readlines(file_new).map { |e| e.chomp }
117
+ data_old = IO.readlines(file_old).map { |e| e.chomp }
118
+ data_new = IO.readlines(file_new).map { |e| e.chomp }
139
119
  end
140
120
 
141
121
  # diff yields lots of pieces, each of which is basically a Block object
@@ -148,16 +128,16 @@ class << Diff::LCS::Ldiff
148
128
 
149
129
  return 0 unless diffs
150
130
 
151
- if (@format == :report) and diffs
131
+ if @format == :report
152
132
  output << "Files #{file_old} and #{file_new} differ\n"
153
133
  return 1
154
134
  end
155
135
 
156
136
  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}"
137
+ ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')
138
+ output << "#{char_old} #{file_old}\t#{ft}\n"
139
+ ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')
140
+ output << "#{char_new} #{file_new}\t#{ft}\n"
161
141
  end
162
142
 
163
143
  # Loop over hunks. If a hunk overlaps with the last hunk, join them.
@@ -171,12 +151,11 @@ class << Diff::LCS::Ldiff
171
151
 
172
152
  diffs.each do |piece|
173
153
  begin
174
- hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines,
175
- file_length_difference)
154
+ hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, file_length_difference)
176
155
  file_length_difference = hunk.file_length_difference
177
156
 
178
157
  next unless oldhunk
179
- next if (@lines > 0) and hunk.merge(oldhunk)
158
+ next if @lines.positive? and hunk.merge(oldhunk)
180
159
 
181
160
  output << oldhunk.diff(@format) << "\n"
182
161
  ensure
@@ -184,12 +163,13 @@ class << Diff::LCS::Ldiff
184
163
  end
185
164
  end
186
165
 
187
- output << oldhunk.diff(@format) << "\n"
166
+ last = oldhunk.diff(@format)
167
+ last << "\n" if last.respond_to?(:end_with?) && !last.end_with?("\n")
188
168
 
189
- if @format == :ed
190
- output.reverse_each { |e| real_output << e.diff(:ed_finish) }
191
- end
169
+ output << last
170
+
171
+ output.reverse_each { |e| real_output << e.diff(:ed_finish) } if @format == :ed
192
172
 
193
- return 1
173
+ 1
194
174
  end
195
175
  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