diff-lcs 1.5.0 → 1.6.0
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 +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
|