diff-lcs 1.1.3 → 1.5.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 +7 -0
- data/.rspec +1 -0
- data/Code-of-Conduct.md +74 -0
- data/Contributing.md +119 -0
- data/History.md +400 -0
- data/{License.rdoc → License.md} +6 -5
- data/Manifest.txt +36 -4
- data/README.rdoc +35 -23
- data/Rakefile +106 -11
- data/bin/htmldiff +7 -4
- data/bin/ldiff +4 -1
- data/docs/COPYING.txt +21 -22
- data/docs/artistic.txt +127 -0
- data/lib/diff/lcs/array.rb +1 -15
- data/lib/diff/lcs/backports.rb +9 -0
- data/lib/diff/lcs/block.rb +4 -18
- data/lib/diff/lcs/callbacks.rb +233 -230
- data/lib/diff/lcs/change.rb +114 -109
- data/lib/diff/lcs/htmldiff.rb +17 -18
- data/lib/diff/lcs/hunk.rb +232 -116
- data/lib/diff/lcs/internals.rb +308 -0
- data/lib/diff/lcs/ldiff.rb +138 -177
- data/lib/diff/lcs/string.rb +1 -15
- data/lib/diff/lcs.rb +597 -963
- data/lib/diff-lcs.rb +1 -3
- data/spec/change_spec.rb +89 -0
- data/spec/diff_spec.rb +32 -16
- data/spec/fixtures/aX +1 -0
- data/spec/fixtures/bXaX +1 -0
- data/spec/fixtures/ds1.csv +50 -0
- data/spec/fixtures/ds2.csv +51 -0
- data/spec/fixtures/ldiff/output.diff +4 -0
- data/spec/fixtures/ldiff/output.diff-c +7 -0
- data/spec/fixtures/ldiff/output.diff-e +3 -0
- data/spec/fixtures/ldiff/output.diff-f +3 -0
- data/spec/fixtures/ldiff/output.diff-u +5 -0
- data/spec/fixtures/ldiff/output.diff.chef +4 -0
- data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
- data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
- data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
- data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
- data/spec/fixtures/new-chef +4 -0
- data/spec/fixtures/new-chef2 +17 -0
- data/spec/fixtures/old-chef +4 -0
- data/spec/fixtures/old-chef2 +14 -0
- data/spec/hunk_spec.rb +83 -0
- data/spec/issues_spec.rb +154 -0
- data/spec/lcs_spec.rb +36 -16
- data/spec/ldiff_spec.rb +87 -0
- data/spec/patch_spec.rb +198 -172
- data/spec/sdiff_spec.rb +99 -89
- data/spec/spec_helper.rb +149 -59
- data/spec/traverse_balanced_spec.rb +191 -167
- data/spec/traverse_sequences_spec.rb +105 -51
- metadata +218 -99
- data/.gemtest +0 -0
- data/History.rdoc +0 -54
- data/diff-lcs.gemspec +0 -51
- data/docs/artistic.html +0 -289
data/lib/diff/lcs/change.rb
CHANGED
@@ -1,151 +1,140 @@
|
|
1
|
-
|
2
|
-
#--
|
3
|
-
# Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca>
|
4
|
-
# adapted from:
|
5
|
-
# Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com>
|
6
|
-
# Smalltalk by Mario I. Wolczko <mario@wolczko.com>
|
7
|
-
# implements McIlroy-Hunt diff algorithm
|
8
|
-
#
|
9
|
-
# This program is free software. It may be redistributed and/or modified under
|
10
|
-
# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
|
11
|
-
# Ruby licence.
|
12
|
-
#
|
13
|
-
# $Id$
|
14
|
-
#++
|
15
|
-
# Provides Diff::LCS::Change and Diff::LCS::ContextChange.
|
16
|
-
|
17
|
-
# Centralises the change test code in Diff::LCS::Change and
|
18
|
-
# Diff::LCS::ContextChange, since it's the same for both classes.
|
19
|
-
module Diff::LCS::ChangeTypeTests
|
20
|
-
def deleting?
|
21
|
-
@action == '-'
|
22
|
-
end
|
1
|
+
# frozen_string_literal: true
|
23
2
|
|
24
|
-
|
25
|
-
|
26
|
-
|
3
|
+
# Represents a simplistic (non-contextual) change. Represents the removal or
|
4
|
+
# addition of an element from either the old or the new sequenced
|
5
|
+
# enumerable.
|
6
|
+
class Diff::LCS::Change
|
7
|
+
IntClass = 1.class # Fixnum is deprecated in Ruby 2.4 # rubocop:disable Naming/ConstantName
|
27
8
|
|
28
|
-
|
29
|
-
|
9
|
+
# The only actions valid for changes are '+' (add), '-' (delete), '='
|
10
|
+
# (no change), '!' (changed), '<' (tail changes from first sequence), or
|
11
|
+
# '>' (tail changes from second sequence). The last two ('<>') are only
|
12
|
+
# found with Diff::LCS::diff and Diff::LCS::sdiff.
|
13
|
+
VALID_ACTIONS = %w(+ - = ! > <).freeze
|
14
|
+
|
15
|
+
def self.valid_action?(action)
|
16
|
+
VALID_ACTIONS.include? action
|
30
17
|
end
|
31
18
|
|
32
|
-
|
33
|
-
|
19
|
+
# Returns the action this Change represents.
|
20
|
+
attr_reader :action
|
21
|
+
|
22
|
+
# Returns the position of the Change.
|
23
|
+
attr_reader :position
|
24
|
+
# Returns the sequence element of the Change.
|
25
|
+
attr_reader :element
|
26
|
+
|
27
|
+
def initialize(*args)
|
28
|
+
@action, @position, @element = *args
|
29
|
+
|
30
|
+
fail "Invalid Change Action '#{@action}'" unless Diff::LCS::Change.valid_action?(@action)
|
31
|
+
fail 'Invalid Position Type' unless @position.kind_of? IntClass
|
34
32
|
end
|
35
33
|
|
36
|
-
def
|
37
|
-
|
34
|
+
def inspect(*_args)
|
35
|
+
"#<#{self.class}: #{to_a.inspect}>"
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
41
|
-
@
|
38
|
+
def to_a
|
39
|
+
[@action, @position, @element]
|
42
40
|
end
|
43
|
-
end
|
44
41
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
alias to_ary to_a
|
43
|
+
|
44
|
+
def self.from_a(arr)
|
45
|
+
arr = arr.flatten(1)
|
46
|
+
case arr.size
|
47
|
+
when 5
|
48
|
+
Diff::LCS::ContextChange.new(*(arr[0...5]))
|
49
|
+
when 3
|
50
|
+
Diff::LCS::Change.new(*(arr[0...3]))
|
51
|
+
else
|
52
|
+
fail 'Invalid change array format provided.'
|
53
|
+
end
|
54
|
+
end
|
55
55
|
|
56
56
|
include Comparable
|
57
|
+
|
57
58
|
def ==(other)
|
58
|
-
(self.
|
59
|
-
|
60
|
-
|
59
|
+
(self.class == other.class) and
|
60
|
+
(action == other.action) and
|
61
|
+
(position == other.position) and
|
62
|
+
(element == other.element)
|
61
63
|
end
|
62
64
|
|
63
65
|
def <=>(other)
|
64
|
-
r =
|
65
|
-
r =
|
66
|
-
r =
|
66
|
+
r = action <=> other.action
|
67
|
+
r = position <=> other.position if r.zero?
|
68
|
+
r = element <=> other.element if r.zero?
|
67
69
|
r
|
68
70
|
end
|
69
71
|
|
70
|
-
def
|
71
|
-
@action
|
72
|
-
@position = position
|
73
|
-
@element = element
|
72
|
+
def adding?
|
73
|
+
@action == '+'
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
[@action, @position, @element]
|
76
|
+
def deleting?
|
77
|
+
@action == '-'
|
79
78
|
end
|
80
79
|
|
81
|
-
def
|
82
|
-
|
80
|
+
def unchanged?
|
81
|
+
@action == '='
|
83
82
|
end
|
84
83
|
|
85
|
-
|
84
|
+
def changed?
|
85
|
+
@action == '!'
|
86
|
+
end
|
87
|
+
|
88
|
+
def finished_a?
|
89
|
+
@action == '>'
|
90
|
+
end
|
91
|
+
|
92
|
+
def finished_b?
|
93
|
+
@action == '<'
|
94
|
+
end
|
86
95
|
end
|
87
96
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
class Diff::LCS::ContextChange
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
# Represents a contextual change. Contains the position and values of the
|
98
|
+
# elements in the old and the new sequenced enumerables as well as the action
|
99
|
+
# taken.
|
100
|
+
class Diff::LCS::ContextChange < Diff::LCS::Change
|
101
|
+
# We don't need these two values.
|
102
|
+
undef :position
|
103
|
+
undef :element
|
104
|
+
|
105
|
+
# Returns the old position being changed.
|
97
106
|
attr_reader :old_position
|
98
|
-
|
107
|
+
# Returns the new position being changed.
|
99
108
|
attr_reader :new_position
|
109
|
+
# Returns the old element being changed.
|
110
|
+
attr_reader :old_element
|
111
|
+
# Returns the new element being changed.
|
100
112
|
attr_reader :new_element
|
101
113
|
|
102
|
-
|
103
|
-
|
104
|
-
def ==(other)
|
105
|
-
(@action == other.action) and
|
106
|
-
(@old_position == other.old_position) and
|
107
|
-
(@new_position == other.new_position) and
|
108
|
-
(@old_element == other.old_element) and
|
109
|
-
(@new_element == other.new_element)
|
110
|
-
end
|
114
|
+
def initialize(*args)
|
115
|
+
@action, @old_position, @old_element, @new_position, @new_element = *args
|
111
116
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
def <=>(other)
|
117
|
-
r = @action <=> other.action
|
118
|
-
r = @old_position <=> other.old_position if r.zero?
|
119
|
-
r = @new_position <=> other.new_position if r.zero?
|
120
|
-
r = @old_element <=> other.old_element if r.zero?
|
121
|
-
r = @new_element <=> other.new_element if r.zero?
|
122
|
-
r
|
123
|
-
end
|
124
|
-
|
125
|
-
def initialize(action, old_position, old_element, new_position, new_element)
|
126
|
-
@action = action
|
127
|
-
@old_position = old_position
|
128
|
-
@old_element = old_element
|
129
|
-
@new_position = new_position
|
130
|
-
@new_element = new_element
|
117
|
+
fail "Invalid Change Action '#{@action}'" unless Diff::LCS::Change.valid_action?(@action)
|
118
|
+
fail 'Invalid (Old) Position Type' unless @old_position.nil? or @old_position.kind_of? IntClass
|
119
|
+
fail 'Invalid (New) Position Type' unless @new_position.nil? or @new_position.kind_of? IntClass
|
131
120
|
end
|
132
121
|
|
133
122
|
def to_a
|
134
|
-
[
|
123
|
+
[
|
124
|
+
@action,
|
125
|
+
[@old_position, @old_element],
|
126
|
+
[@new_position, @new_element]
|
127
|
+
]
|
135
128
|
end
|
136
129
|
|
137
|
-
|
130
|
+
alias to_ary to_a
|
131
|
+
|
138
132
|
def self.from_a(arr)
|
139
|
-
|
140
|
-
Diff::LCS::ContextChange.new(arr[0], arr[1], arr[2], arr[3], arr[4])
|
141
|
-
else
|
142
|
-
Diff::LCS::ContextChange.new(arr[0], arr[1][0], arr[1][1], arr[2][0],
|
143
|
-
arr[2][1])
|
144
|
-
end
|
133
|
+
Diff::LCS::Change.from_a(arr)
|
145
134
|
end
|
146
135
|
|
147
|
-
|
148
|
-
|
136
|
+
# Simplifies a context change for use in some diff callbacks. '<' actions
|
137
|
+
# are converted to '-' and '>' actions are converted to '+'.
|
149
138
|
def self.simplify(event)
|
150
139
|
ea = event.to_a
|
151
140
|
|
@@ -165,5 +154,21 @@ class Diff::LCS::ContextChange
|
|
165
154
|
Diff::LCS::ContextChange.from_a(ea)
|
166
155
|
end
|
167
156
|
|
168
|
-
|
157
|
+
def ==(other)
|
158
|
+
(self.class == other.class) and
|
159
|
+
(@action == other.action) and
|
160
|
+
(@old_position == other.old_position) and
|
161
|
+
(@new_position == other.new_position) and
|
162
|
+
(@old_element == other.old_element) and
|
163
|
+
(@new_element == other.new_element)
|
164
|
+
end
|
165
|
+
|
166
|
+
def <=>(other)
|
167
|
+
r = @action <=> other.action
|
168
|
+
r = @old_position <=> other.old_position if r.zero?
|
169
|
+
r = @new_position <=> other.new_position if r.zero?
|
170
|
+
r = @old_element <=> other.old_element if r.zero?
|
171
|
+
r = @new_element <=> other.new_element if r.zero?
|
172
|
+
r
|
173
|
+
end
|
169
174
|
end
|
data/lib/diff/lcs/htmldiff.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cgi'
|
4
4
|
|
5
|
+
# Produce a simple HTML diff view.
|
5
6
|
class Diff::LCS::HTMLDiff
|
6
7
|
class << self
|
7
8
|
attr_accessor :can_expand_tabs #:nodoc:
|
8
9
|
end
|
9
10
|
self.can_expand_tabs = true
|
10
11
|
|
11
|
-
class Callbacks
|
12
|
+
class Callbacks #:nodoc:
|
12
13
|
attr_accessor :output
|
13
14
|
attr_accessor :match_class
|
14
15
|
attr_accessor :only_a_class
|
@@ -18,14 +19,14 @@ class Diff::LCS::HTMLDiff
|
|
18
19
|
@output = output
|
19
20
|
options ||= {}
|
20
21
|
|
21
|
-
@match_class = options[:match_class] ||
|
22
|
-
@only_a_class = options[:only_a_class] ||
|
23
|
-
@only_b_class = options[:only_b_class] ||
|
22
|
+
@match_class = options[:match_class] || 'match'
|
23
|
+
@only_a_class = options[:only_a_class] || 'only_a'
|
24
|
+
@only_b_class = options[:only_b_class] || 'only_b'
|
24
25
|
end
|
25
26
|
|
26
27
|
def htmlize(element, css_class)
|
27
|
-
element =
|
28
|
-
%Q
|
28
|
+
element = ' ' if element.empty?
|
29
|
+
%Q(<pre class="#{__send__(css_class)}">#{element}</pre>\n)
|
29
30
|
end
|
30
31
|
private :htmlize
|
31
32
|
|
@@ -49,8 +50,8 @@ class Diff::LCS::HTMLDiff
|
|
49
50
|
:expand_tabs => nil,
|
50
51
|
:output => nil,
|
51
52
|
:css => nil,
|
52
|
-
:title => nil
|
53
|
-
}
|
53
|
+
:title => nil
|
54
|
+
}.freeze
|
54
55
|
|
55
56
|
DEFAULT_CSS = <<-CSS
|
56
57
|
body { margin: 0; }
|
@@ -96,13 +97,13 @@ h1 { margin-left: 2em; }
|
|
96
97
|
|
97
98
|
def verify_options
|
98
99
|
@options[:expand_tabs] ||= 4
|
99
|
-
@options[:expand_tabs] = 4 if @options[:expand_tabs]
|
100
|
+
@options[:expand_tabs] = 4 if @options[:expand_tabs].negative?
|
100
101
|
|
101
102
|
@options[:output] ||= $stdout
|
102
103
|
|
103
104
|
@options[:css] ||= DEFAULT_CSS.dup
|
104
105
|
|
105
|
-
@options[:title] ||=
|
106
|
+
@options[:title] ||= 'diff'
|
106
107
|
end
|
107
108
|
private :verify_options
|
108
109
|
|
@@ -111,16 +112,16 @@ h1 { margin-left: 2em; }
|
|
111
112
|
def run
|
112
113
|
verify_options
|
113
114
|
|
114
|
-
if @options[:expand_tabs]
|
115
|
+
if @options[:expand_tabs].positive? && self.class.can_expand_tabs
|
115
116
|
formatter = Text::Format.new
|
116
117
|
formatter.tabstop = @options[:expand_tabs]
|
117
118
|
|
118
|
-
@left
|
119
|
-
@right
|
119
|
+
@left.map! do |line| formatter.expand(line.chomp) end
|
120
|
+
@right.map! do |line| formatter.expand(line.chomp) end
|
120
121
|
end
|
121
122
|
|
122
|
-
@left.map!
|
123
|
-
@right.map!
|
123
|
+
@left.map! do |line| CGI.escapeHTML(line.chomp) end
|
124
|
+
@right.map! do |line| CGI.escapeHTML(line.chomp) end
|
124
125
|
|
125
126
|
@options[:output] << <<-OUTPUT
|
126
127
|
<html>
|
@@ -147,5 +148,3 @@ h1 { margin-left: 2em; }
|
|
147
148
|
OUTPUT
|
148
149
|
end
|
149
150
|
end
|
150
|
-
|
151
|
-
# vim: ft=ruby
|