diff-lcs 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +491 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +74 -0
- data/CONTRIBUTORS.md +48 -0
- data/Contributing.md +45 -90
- data/{License.md → LICENCE.md} +6 -4
- data/Manifest.txt +7 -4
- data/README.md +92 -0
- data/Rakefile +43 -66
- data/SECURITY.md +41 -0
- data/bin/htmldiff +4 -4
- data/docs/artistic.txt +1 -1
- data/lib/diff/lcs/array.rb +1 -1
- data/lib/diff/lcs/backports.rb +2 -2
- data/lib/diff/lcs/block.rb +4 -4
- data/lib/diff/lcs/callbacks.rb +9 -7
- data/lib/diff/lcs/change.rb +20 -20
- data/lib/diff/lcs/htmldiff.rb +26 -16
- data/lib/diff/lcs/hunk.rb +66 -45
- data/lib/diff/lcs/internals.rb +17 -17
- data/lib/diff/lcs/ldiff.rb +86 -74
- data/lib/diff/lcs.rb +66 -63
- data/lib/diff-lcs.rb +1 -1
- data/spec/change_spec.rb +50 -50
- data/spec/diff_spec.rb +14 -14
- data/spec/hunk_spec.rb +20 -20
- data/spec/issues_spec.rb +76 -70
- data/spec/lcs_spec.rb +11 -11
- data/spec/ldiff_spec.rb +30 -17
- data/spec/patch_spec.rb +84 -84
- data/spec/sdiff_spec.rb +111 -109
- data/spec/spec_helper.rb +76 -74
- data/spec/traverse_balanced_spec.rb +191 -189
- data/spec/traverse_sequences_spec.rb +31 -31
- metadata +55 -30
- data/Code-of-Conduct.md +0 -74
- data/History.md +0 -400
- data/README.rdoc +0 -84
data/lib/diff/lcs/internals.rb
CHANGED
@@ -13,7 +13,7 @@ class << Diff::LCS
|
|
13
13
|
|
14
14
|
if block
|
15
15
|
callbacks.diffs.map do |hunk|
|
16
|
-
if hunk.
|
16
|
+
if hunk.is_a? Array
|
17
17
|
hunk.map { |hunk_block| block[hunk_block] }
|
18
18
|
else
|
19
19
|
block[hunk]
|
@@ -45,14 +45,14 @@ class << Diff::LCS::Internals
|
|
45
45
|
vector = []
|
46
46
|
|
47
47
|
# Collect any common elements at the beginning...
|
48
|
-
while (a_start <= a_finish)
|
48
|
+
while (a_start <= a_finish) && (b_start <= b_finish) && (a[a_start] == b[b_start])
|
49
49
|
vector[a_start] = b_start
|
50
50
|
a_start += 1
|
51
51
|
b_start += 1
|
52
52
|
end
|
53
53
|
|
54
54
|
# Now the end...
|
55
|
-
while (a_start <= a_finish)
|
55
|
+
while (a_start <= a_finish) && (b_start <= b_finish) && (a[a_finish] == b[b_finish])
|
56
56
|
vector[a_finish] = b_finish
|
57
57
|
a_finish -= 1
|
58
58
|
b_finish -= 1
|
@@ -63,8 +63,8 @@ class << Diff::LCS::Internals
|
|
63
63
|
b_matches = position_hash(b, b_start..b_finish)
|
64
64
|
|
65
65
|
thresh = []
|
66
|
-
links
|
67
|
-
string = a.
|
66
|
+
links = []
|
67
|
+
string = a.is_a?(String)
|
68
68
|
|
69
69
|
(a_start..a_finish).each do |i|
|
70
70
|
ai = string ? a[i, 1] : a[i]
|
@@ -75,7 +75,7 @@ class << Diff::LCS::Internals
|
|
75
75
|
# it may have an optimization purpose
|
76
76
|
# An attempt to remove it: https://github.com/halostatue/diff-lcs/pull/72
|
77
77
|
# Why it is reintroduced: https://github.com/halostatue/diff-lcs/issues/78
|
78
|
-
if k
|
78
|
+
if k && (thresh[k] > j) && (thresh[k - 1] < j)
|
79
79
|
thresh[k] = j
|
80
80
|
else
|
81
81
|
k = replace_next_larger(thresh, j, k)
|
@@ -100,7 +100,7 @@ class << Diff::LCS::Internals
|
|
100
100
|
# the object form of same) and detection of whether the patchset represents
|
101
101
|
# changes to be made.
|
102
102
|
def analyze_patchset(patchset, depth = 0)
|
103
|
-
fail
|
103
|
+
fail "Patchset too complex" if depth > 1
|
104
104
|
|
105
105
|
has_changes = false
|
106
106
|
new_patchset = []
|
@@ -145,7 +145,7 @@ class << Diff::LCS::Internals
|
|
145
145
|
# Diff::LCS::Change as its source, as an array will cause the creation
|
146
146
|
# of one of the above.
|
147
147
|
def intuit_diff_direction(src, patchset, limit = nil)
|
148
|
-
string = src.
|
148
|
+
string = src.is_a?(String)
|
149
149
|
count = left_match = left_miss = right_match = right_miss = 0
|
150
150
|
|
151
151
|
patchset.each do |change|
|
@@ -157,22 +157,22 @@ class << Diff::LCS::Internals
|
|
157
157
|
re = string ? src[change.new_position, 1] : src[change.new_position]
|
158
158
|
|
159
159
|
case change.action
|
160
|
-
when
|
160
|
+
when "-" # Remove details from the old string
|
161
161
|
if le == change.old_element
|
162
162
|
left_match += 1
|
163
163
|
else
|
164
164
|
left_miss += 1
|
165
165
|
end
|
166
|
-
when
|
166
|
+
when "+"
|
167
167
|
if re == change.new_element
|
168
168
|
right_match += 1
|
169
169
|
else
|
170
170
|
right_miss += 1
|
171
171
|
end
|
172
|
-
when
|
172
|
+
when "="
|
173
173
|
left_miss += 1 if le != change.old_element
|
174
174
|
right_miss += 1 if re != change.new_element
|
175
|
-
when
|
175
|
+
when "!"
|
176
176
|
if le == change.old_element
|
177
177
|
left_match += 1
|
178
178
|
elsif re == change.new_element
|
@@ -189,19 +189,19 @@ class << Diff::LCS::Internals
|
|
189
189
|
element = string ? src[change.position, 1] : src[change.position]
|
190
190
|
|
191
191
|
case change.action
|
192
|
-
when
|
192
|
+
when "-"
|
193
193
|
if element == change.element
|
194
194
|
left_match += 1
|
195
195
|
else
|
196
196
|
left_miss += 1
|
197
197
|
end
|
198
|
-
when
|
198
|
+
when "+"
|
199
199
|
if element == change.element
|
200
200
|
right_match += 1
|
201
201
|
else
|
202
202
|
right_miss += 1
|
203
203
|
end
|
204
|
-
when
|
204
|
+
when "="
|
205
205
|
if element != change.element
|
206
206
|
left_miss += 1
|
207
207
|
right_miss += 1
|
@@ -251,7 +251,7 @@ enumerable as either source or destination value."
|
|
251
251
|
# This operation preserves the sort order.
|
252
252
|
def replace_next_larger(enum, value, last_index = nil)
|
253
253
|
# Off the end?
|
254
|
-
if enum.empty?
|
254
|
+
if enum.empty? || (value > enum[-1])
|
255
255
|
enum << value
|
256
256
|
return enum.size - 1
|
257
257
|
end
|
@@ -296,7 +296,7 @@ enumerable as either source or destination value."
|
|
296
296
|
# positions it occupies in the Enumerable, optionally restricted to the
|
297
297
|
# elements specified in the range of indexes specified by +interval+.
|
298
298
|
def position_hash(enum, interval)
|
299
|
-
string = enum.
|
299
|
+
string = enum.is_a?(String)
|
300
300
|
hash = Hash.new { |h, k| h[k] = [] }
|
301
301
|
interval.each do |i|
|
302
302
|
k = string ? enum[i, 1] : enum[i]
|
data/lib/diff/lcs/ldiff.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require 'diff/lcs/hunk'
|
3
|
+
require "optparse"
|
4
|
+
require "diff/lcs/hunk"
|
6
5
|
|
7
|
-
module Diff::LCS::Ldiff
|
6
|
+
module Diff::LCS::Ldiff # :nodoc:
|
7
|
+
# standard:disable Layout/HeredocIndentation
|
8
8
|
BANNER = <<-COPYRIGHT
|
9
9
|
ldiff #{Diff::LCS::VERSION}
|
10
10
|
Copyright 2004-2019 Austin Ziegler
|
@@ -16,60 +16,67 @@ ldiff #{Diff::LCS::VERSION}
|
|
16
16
|
the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
|
17
17
|
MIT licence.
|
18
18
|
COPYRIGHT
|
19
|
-
|
19
|
+
# standard:enable Layout/HeredocIndentation
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
InputInfo = Struct.new(:filename, :data, :stat) do
|
22
|
+
def initialize(filename)
|
23
|
+
super(filename, ::File.read(filename), ::File.stat(filename))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_reader :format, :lines # :nodoc:
|
29
|
+
attr_reader :file_old, :file_new # :nodoc:
|
30
|
+
attr_reader :data_old, :data_new # :nodoc:
|
31
|
+
end
|
25
32
|
|
26
|
-
def run(args, _input = $stdin, output = $stdout, error = $stderr)
|
33
|
+
def self.run(args, _input = $stdin, output = $stdout, error = $stderr) # :nodoc:
|
27
34
|
@binary = nil
|
28
35
|
|
29
36
|
args.options do |o|
|
30
37
|
o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile"
|
31
|
-
o.separator
|
38
|
+
o.separator ""
|
32
39
|
o.on(
|
33
|
-
|
34
|
-
|
40
|
+
"-c", "-C", "--context [LINES]", Integer,
|
41
|
+
"Displays a context diff with LINES lines", "of context. Default 3 lines."
|
35
42
|
) do |ctx|
|
36
43
|
@format = :context
|
37
|
-
@lines
|
44
|
+
@lines = ctx || 3
|
38
45
|
end
|
39
46
|
o.on(
|
40
|
-
|
41
|
-
|
47
|
+
"-u", "-U", "--unified [LINES]", Integer,
|
48
|
+
"Displays a unified diff with LINES lines", "of context. Default 3 lines."
|
42
49
|
) do |ctx|
|
43
50
|
@format = :unified
|
44
|
-
@lines
|
51
|
+
@lines = ctx || 3
|
45
52
|
end
|
46
|
-
o.on(
|
53
|
+
o.on("-e", "Creates an 'ed' script to change", "oldfile to newfile.") do |_ctx|
|
47
54
|
@format = :ed
|
48
55
|
end
|
49
|
-
o.on(
|
56
|
+
o.on("-f", "Creates an 'ed' script to change", "oldfile to newfile in reverse order.") do |_ctx|
|
50
57
|
@format = :reverse_ed
|
51
58
|
end
|
52
59
|
o.on(
|
53
|
-
|
54
|
-
|
60
|
+
"-a", "--text",
|
61
|
+
"Treat the files as text and compare them", "line-by-line, even if they do not seem", "to be text."
|
55
62
|
) do |_txt|
|
56
63
|
@binary = false
|
57
64
|
end
|
58
|
-
o.on(
|
65
|
+
o.on("--binary", "Treats the files as binary.") do |_bin|
|
59
66
|
@binary = true
|
60
67
|
end
|
61
|
-
o.on(
|
68
|
+
o.on("-q", "--brief", "Report only whether or not the files", "differ, not the details.") do |_ctx|
|
62
69
|
@format = :report
|
63
70
|
end
|
64
|
-
o.on_tail(
|
71
|
+
o.on_tail("--help", "Shows this text.") do
|
65
72
|
error << o
|
66
73
|
return 0
|
67
74
|
end
|
68
|
-
o.on_tail(
|
75
|
+
o.on_tail("--version", "Shows the version of Diff::LCS.") do
|
69
76
|
error << Diff::LCS::Ldiff::BANNER
|
70
77
|
return 0
|
71
78
|
end
|
72
|
-
o.on_tail
|
79
|
+
o.on_tail ""
|
73
80
|
o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.'
|
74
81
|
o.parse!
|
75
82
|
end
|
@@ -81,91 +88,96 @@ class << Diff::LCS::Ldiff
|
|
81
88
|
|
82
89
|
# Defaults are for old-style diff
|
83
90
|
@format ||= :old
|
84
|
-
@lines
|
91
|
+
@lines ||= 0
|
85
92
|
|
86
93
|
file_old, file_new = *ARGV
|
94
|
+
diff?(
|
95
|
+
InputInfo.new(file_old),
|
96
|
+
InputInfo.new(file_new),
|
97
|
+
@format,
|
98
|
+
output,
|
99
|
+
binary: @binary,
|
100
|
+
lines: @lines
|
101
|
+
) ? 1 : 0
|
102
|
+
end
|
87
103
|
|
88
|
-
|
104
|
+
def self.diff?(info_old, info_new, format, output, binary: nil, lines: 0)
|
105
|
+
case format
|
89
106
|
when :context
|
90
|
-
char_old =
|
91
|
-
char_new =
|
107
|
+
char_old = "*" * 3
|
108
|
+
char_new = "-" * 3
|
92
109
|
when :unified
|
93
|
-
char_old =
|
94
|
-
char_new =
|
110
|
+
char_old = "-" * 3
|
111
|
+
char_new = "+" * 3
|
95
112
|
end
|
96
113
|
|
97
114
|
# After we've read up to a certain point in each file, the number of
|
98
115
|
# items we've read from each file will differ by FLD (could be 0).
|
99
116
|
file_length_difference = 0
|
100
117
|
|
101
|
-
data_old = IO.read(file_old)
|
102
|
-
data_new = IO.read(file_new)
|
103
|
-
|
104
118
|
# Test binary status
|
105
|
-
if
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
unless @binary
|
112
|
-
data_old = data_old.lines.to_a
|
113
|
-
data_new = data_new.lines.to_a
|
119
|
+
if binary.nil?
|
120
|
+
old_bin = info_old.data[0, 4096].include?("\0")
|
121
|
+
new_bin = info_new.data[0, 4096].include?("\0")
|
122
|
+
binary = old_bin || new_bin
|
114
123
|
end
|
115
124
|
|
116
125
|
# diff yields lots of pieces, each of which is basically a Block object
|
117
|
-
if
|
118
|
-
|
126
|
+
if binary
|
127
|
+
has_diffs = (info_old.data != info_new.data)
|
128
|
+
if format != :report
|
129
|
+
if has_diffs
|
130
|
+
output << "Binary files #{info_old.filename} and #{info_new.filename} differ\n"
|
131
|
+
return true
|
132
|
+
end
|
133
|
+
return false
|
134
|
+
end
|
119
135
|
else
|
136
|
+
data_old = info_old.data.lines.to_a
|
137
|
+
data_new = info_new.data.lines.to_a
|
120
138
|
diffs = Diff::LCS.diff(data_old, data_new)
|
121
|
-
|
139
|
+
return false if diffs.empty?
|
122
140
|
end
|
123
141
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
output
|
142
|
+
case format
|
143
|
+
when :report
|
144
|
+
output << "Files #{info_old.filename} and #{info_new.filename} differ\n"
|
145
|
+
return true
|
146
|
+
when :unified, :context
|
147
|
+
ft = info_old.stat.mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.000000000 %z")
|
148
|
+
output << "#{char_old} #{info_old.filename}\t#{ft}\n"
|
149
|
+
ft = info_new.stat.mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.000000000 %z")
|
150
|
+
output << "#{char_new} #{info_new.filename}\t#{ft}\n"
|
151
|
+
when :ed
|
152
|
+
real_output = output
|
153
|
+
output = []
|
136
154
|
end
|
137
155
|
|
138
156
|
# Loop over hunks. If a hunk overlaps with the last hunk, join them.
|
139
157
|
# Otherwise, print out the old one.
|
140
158
|
oldhunk = hunk = nil
|
141
|
-
|
142
|
-
if @format == :ed
|
143
|
-
real_output = output
|
144
|
-
output = []
|
145
|
-
end
|
146
|
-
|
147
159
|
diffs.each do |piece|
|
148
|
-
begin
|
149
|
-
hunk = Diff::LCS::Hunk.new(data_old, data_new, piece,
|
160
|
+
begin
|
161
|
+
hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, lines, file_length_difference)
|
150
162
|
file_length_difference = hunk.file_length_difference
|
151
163
|
|
152
164
|
next unless oldhunk
|
153
|
-
next if
|
165
|
+
next if lines.positive? && hunk.merge(oldhunk)
|
154
166
|
|
155
|
-
output << oldhunk.diff(
|
156
|
-
output << "\n" if
|
167
|
+
output << oldhunk.diff(format)
|
168
|
+
output << "\n" if format == :unified
|
157
169
|
ensure
|
158
170
|
oldhunk = hunk
|
159
171
|
end
|
160
172
|
end
|
161
173
|
|
162
|
-
last = oldhunk.diff(
|
163
|
-
last << "\n"
|
174
|
+
last = oldhunk.diff(format, true)
|
175
|
+
last << "\n" unless last.is_a?(Diff::LCS::Hunk) || last.empty? || last.end_with?("\n")
|
164
176
|
|
165
177
|
output << last
|
166
178
|
|
167
|
-
output.reverse_each { |e| real_output << e.diff(:ed_finish) } if
|
179
|
+
output.reverse_each { |e| real_output << e.diff(:ed_finish, e == output[0]) } if format == :ed
|
168
180
|
|
169
|
-
|
181
|
+
true
|
170
182
|
end
|
171
183
|
end
|