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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/Code-of-Conduct.md +74 -0
  4. data/Contributing.md +119 -0
  5. data/History.md +400 -0
  6. data/{License.rdoc → License.md} +6 -5
  7. data/Manifest.txt +36 -4
  8. data/README.rdoc +35 -23
  9. data/Rakefile +106 -11
  10. data/bin/htmldiff +7 -4
  11. data/bin/ldiff +4 -1
  12. data/docs/COPYING.txt +21 -22
  13. data/docs/artistic.txt +127 -0
  14. data/lib/diff/lcs/array.rb +1 -15
  15. data/lib/diff/lcs/backports.rb +9 -0
  16. data/lib/diff/lcs/block.rb +4 -18
  17. data/lib/diff/lcs/callbacks.rb +233 -230
  18. data/lib/diff/lcs/change.rb +114 -109
  19. data/lib/diff/lcs/htmldiff.rb +17 -18
  20. data/lib/diff/lcs/hunk.rb +232 -116
  21. data/lib/diff/lcs/internals.rb +308 -0
  22. data/lib/diff/lcs/ldiff.rb +138 -177
  23. data/lib/diff/lcs/string.rb +1 -15
  24. data/lib/diff/lcs.rb +597 -963
  25. data/lib/diff-lcs.rb +1 -3
  26. data/spec/change_spec.rb +89 -0
  27. data/spec/diff_spec.rb +32 -16
  28. data/spec/fixtures/aX +1 -0
  29. data/spec/fixtures/bXaX +1 -0
  30. data/spec/fixtures/ds1.csv +50 -0
  31. data/spec/fixtures/ds2.csv +51 -0
  32. data/spec/fixtures/ldiff/output.diff +4 -0
  33. data/spec/fixtures/ldiff/output.diff-c +7 -0
  34. data/spec/fixtures/ldiff/output.diff-e +3 -0
  35. data/spec/fixtures/ldiff/output.diff-f +3 -0
  36. data/spec/fixtures/ldiff/output.diff-u +5 -0
  37. data/spec/fixtures/ldiff/output.diff.chef +4 -0
  38. data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
  39. data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
  40. data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
  41. data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
  42. data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
  43. data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
  44. data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
  45. data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
  46. data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
  47. data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
  48. data/spec/fixtures/new-chef +4 -0
  49. data/spec/fixtures/new-chef2 +17 -0
  50. data/spec/fixtures/old-chef +4 -0
  51. data/spec/fixtures/old-chef2 +14 -0
  52. data/spec/hunk_spec.rb +83 -0
  53. data/spec/issues_spec.rb +154 -0
  54. data/spec/lcs_spec.rb +36 -16
  55. data/spec/ldiff_spec.rb +87 -0
  56. data/spec/patch_spec.rb +198 -172
  57. data/spec/sdiff_spec.rb +99 -89
  58. data/spec/spec_helper.rb +149 -59
  59. data/spec/traverse_balanced_spec.rb +191 -167
  60. data/spec/traverse_sequences_spec.rb +105 -51
  61. metadata +218 -99
  62. data/.gemtest +0 -0
  63. data/History.rdoc +0 -54
  64. data/diff-lcs.gemspec +0 -51
  65. data/docs/artistic.html +0 -289
@@ -1,151 +1,140 @@
1
- #! /usr/env/bin ruby
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
- def adding?
25
- @action == '+'
26
- end
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
- def unchanged?
29
- @action == '='
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
- def changed?
33
- @changed == '!'
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 finished_a?
37
- @changed == '>'
34
+ def inspect(*_args)
35
+ "#<#{self.class}: #{to_a.inspect}>"
38
36
  end
39
37
 
40
- def finished_b?
41
- @changed == '<'
38
+ def to_a
39
+ [@action, @position, @element]
42
40
  end
43
- end
44
41
 
45
- # Represents a simplistic (non-contextual) change. Represents the removal or
46
- # addition of an element from either the old or the new sequenced enumerable.
47
- class Diff::LCS::Change
48
- # Returns the action this Change represents. Can be '+' (#adding?), '-'
49
- # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When created by
50
- # Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' (#finished_a?) or
51
- # '<' (#finished_b?).
52
- attr_reader :action
53
- attr_reader :position
54
- attr_reader :element
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.action == other.action) and
59
- (self.position == other.position) and
60
- (self.element == other.element)
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 = self.action <=> other.action
65
- r = self.position <=> other.position if r.zero?
66
- r = self.element <=> other.element if r.zero?
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 initialize(action, position, element)
71
- @action = action
72
- @position = position
73
- @element = element
72
+ def adding?
73
+ @action == '+'
74
74
  end
75
75
 
76
- # Creates a Change from an array produced by Change#to_a.
77
- def to_a
78
- [@action, @position, @element]
76
+ def deleting?
77
+ @action == '-'
79
78
  end
80
79
 
81
- def self.from_a(arr)
82
- Diff::LCS::Change.new(arr[0], arr[1], arr[2])
80
+ def unchanged?
81
+ @action == '='
83
82
  end
84
83
 
85
- include Diff::LCS::ChangeTypeTests
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
- # Represents a contextual change. Contains the position and values of the
89
- # elements in the old and the new sequenced enumerables as well as the action
90
- # taken.
91
- class Diff::LCS::ContextChange
92
- # Returns the action this Change represents. Can be '+' (#adding?), '-'
93
- # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When
94
- # created by Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>'
95
- # (#finished_a?) or '<' (#finished_b?).
96
- attr_reader :action
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
- attr_reader :old_element
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
- include Comparable
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
- def inspect(*args)
113
- %Q(#<#{self.class.name}:#{__id__} @action=#{action} positions=#{old_position},#{new_position} elements=#{old_element.inspect},#{new_element.inspect}>)
114
- end
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
- [@action, [@old_position, @old_element], [@new_position, @new_element]]
123
+ [
124
+ @action,
125
+ [@old_position, @old_element],
126
+ [@new_position, @new_element]
127
+ ]
135
128
  end
136
129
 
137
- # Creates a ContextChange from an array produced by ContextChange#to_a.
130
+ alias to_ary to_a
131
+
138
132
  def self.from_a(arr)
139
- if arr.size == 5
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
- # Simplifies a context change for use in some diff callbacks. '<' actions
148
- # are converted to '-' and '>' actions are converted to '+'.
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
- include Diff::LCS::ChangeTypeTests
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
@@ -1,14 +1,15 @@
1
- # -*- ruby encoding: utf-8 -*-
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] || "match"
22
- @only_a_class = options[:only_a_class] || "only_a"
23
- @only_b_class = options[:only_b_class] || "only_b"
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 = "&nbsp;" if element.empty?
28
- %Q|<pre class="#{__send__(css_class)}">#{element}</pre>\n|
28
+ element = '&nbsp;' 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] < 0
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] ||= "diff"
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] > 0 && self.class.can_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 = left.map { |line| formatter.expand(line.chomp) }
119
- @right = right.map { |line| formatter.expand(line.chomp) }
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! { |line| CGI.escapeHTML(line.chomp) }
123
- @right.map! { |line| CGI.escapeHTML(line.chomp) }
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