diff-lcs 1.1.2 → 1.1.3

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.
@@ -0,0 +1,284 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'pathname'
5
+
6
+ file = Pathname.new(__FILE__).expand_path
7
+ path = file.parent
8
+ parent = path.parent
9
+
10
+ $:.unshift parent.join('lib')
11
+
12
+ require 'diff-lcs'
13
+
14
+ module Diff::LCS::SpecHelper
15
+ def seq1
16
+ %w(a b c e h j l m n p)
17
+ end
18
+
19
+ def skipped_seq1
20
+ %w(a h n p)
21
+ end
22
+
23
+ def seq2
24
+ %w(b c d e f j k l m r s t)
25
+ end
26
+
27
+ def skipped_seq2
28
+ %w(d f k r s t)
29
+ end
30
+
31
+ def word_sequence
32
+ %w(abcd efgh ijkl mnopqrstuvwxyz)
33
+ end
34
+
35
+ def correct_lcs
36
+ %w(b c e j l m)
37
+ end
38
+
39
+ def correct_forward_diff
40
+ [
41
+ [ [ '-', 0, 'a' ] ],
42
+ [ [ '+', 2, 'd' ] ],
43
+ [ [ '-', 4, 'h' ],
44
+ [ '+', 4, 'f' ] ],
45
+ [ [ '+', 6, 'k' ] ],
46
+ [ [ '-', 8, 'n' ],
47
+ [ '-', 9, 'p' ],
48
+ [ '+', 9, 'r' ],
49
+ [ '+', 10, 's' ],
50
+ [ '+', 11, 't' ] ]
51
+ ]
52
+ end
53
+
54
+ def correct_backward_diff
55
+ [
56
+ [ [ '+', 0, 'a' ] ],
57
+ [ [ '-', 2, 'd' ] ],
58
+ [ [ '-', 4, 'f' ],
59
+ [ '+', 4, 'h' ] ],
60
+ [ [ '-', 6, 'k' ] ],
61
+ [
62
+ [ '-', 9, 'r' ],
63
+ [ '-', 10, 's' ],
64
+ [ '+', 8, 'n' ],
65
+ [ '-', 11, 't' ],
66
+ [ '+', 9, 'p' ] ]
67
+ ]
68
+ end
69
+
70
+ def correct_forward_sdiff
71
+ [
72
+ [ '-', [ 0, 'a' ], [ 0, nil ] ],
73
+ [ '=', [ 1, 'b' ], [ 0, 'b' ] ],
74
+ [ '=', [ 2, 'c' ], [ 1, 'c' ] ],
75
+ [ '+', [ 3, nil ], [ 2, 'd' ] ],
76
+ [ '=', [ 3, 'e' ], [ 3, 'e' ] ],
77
+ [ '!', [ 4, 'h' ], [ 4, 'f' ] ],
78
+ [ '=', [ 5, 'j' ], [ 5, 'j' ] ],
79
+ [ '+', [ 6, nil ], [ 6, 'k' ] ],
80
+ [ '=', [ 6, 'l' ], [ 7, 'l' ] ],
81
+ [ '=', [ 7, 'm' ], [ 8, 'm' ] ],
82
+ [ '!', [ 8, 'n' ], [ 9, 'r' ] ],
83
+ [ '!', [ 9, 'p' ], [ 10, 's' ] ],
84
+ [ '+', [ 10, nil ], [ 11, 't' ] ]
85
+ ]
86
+ end
87
+
88
+ def reverse_sdiff(forward_sdiff)
89
+ forward_sdiff.map { |line|
90
+ line[1], line[2] = line[2], line[1]
91
+ case line[0]
92
+ when '-' then line[0] = '+'
93
+ when '+' then line[0] = '-'
94
+ end
95
+ line
96
+ }
97
+ end
98
+
99
+ def change_diff(diff)
100
+ map_diffs(diff, Diff::LCS::Change)
101
+ end
102
+
103
+ def context_diff(diff)
104
+ map_diffs(diff, Diff::LCS::ContextChange)
105
+ end
106
+
107
+ def format_diffs(diffs)
108
+ diffs.map do |e|
109
+ if e.kind_of?(Array)
110
+ e.map { |f| f.to_a.join }.join(", ")
111
+ else
112
+ e.to_a.join
113
+ end
114
+ end.join("\n")
115
+ end
116
+
117
+ def map_diffs(diffs, klass = Diff::LCS::ContextChange)
118
+ diffs.map do |chunks|
119
+ if klass == Diff::LCS::ContextChange
120
+ klass.from_a(chunks)
121
+ else
122
+ chunks.map { |changes| klass.from_a(changes) }
123
+ end
124
+ end
125
+ end
126
+
127
+ def balanced_traversal(s1, s2, callback_type)
128
+ callback = __send__(callback_type)
129
+ Diff::LCS.traverse_balanced(s1, s2, callback)
130
+ callback
131
+ end
132
+
133
+ def balanced_reverse(change_result)
134
+ new_result = []
135
+ change_result.each { |line|
136
+ line = [ line[0], line[2], line[1] ]
137
+ case line[0]
138
+ when '<'
139
+ line[0] = '>'
140
+ when '>'
141
+ line[0] = '<'
142
+ end
143
+ new_result << line
144
+ }
145
+ new_result.sort_by { |line| [ line[1], line[2] ] }
146
+ end
147
+
148
+ def map_to_no_change(change_result)
149
+ new_result = []
150
+ change_result.each { |line|
151
+ case line[0]
152
+ when '!'
153
+ new_result << [ '<', line[1], line[2] ]
154
+ new_result << [ '>', line[1] + 1, line[2] ]
155
+ else
156
+ new_result << line
157
+ end
158
+ }
159
+ new_result
160
+ end
161
+
162
+
163
+ def simple_callback
164
+ callbacks = Object.new
165
+ class << callbacks
166
+ attr_reader :matched_a
167
+ attr_reader :matched_b
168
+ attr_reader :discards_a
169
+ attr_reader :discards_b
170
+ attr_reader :done_a
171
+ attr_reader :done_b
172
+
173
+ def reset
174
+ @matched_a = []
175
+ @matched_b = []
176
+ @discards_a = []
177
+ @discards_b = []
178
+ @done_a = []
179
+ @done_b = []
180
+ end
181
+
182
+ def match(event)
183
+ @matched_a << event.old_element
184
+ @matched_b << event.new_element
185
+ end
186
+
187
+ def discard_b(event)
188
+ @discards_b << event.new_element
189
+ end
190
+
191
+ def discard_a(event)
192
+ @discards_a << event.old_element
193
+ end
194
+
195
+ def finished_a(event)
196
+ @done_a << [event.old_element, event.old_position,
197
+ event.new_element, event.new_position]
198
+ end
199
+
200
+ def finished_b(event)
201
+ p "called #finished_b"
202
+ @done_b << [event.old_element, event.old_position,
203
+ event.new_element, event.new_position]
204
+ end
205
+ end
206
+ callbacks.reset
207
+ callbacks
208
+ end
209
+
210
+ def simple_callback_no_finishers
211
+ simple = simple_callback
212
+ class << simple
213
+ undef :finished_a
214
+ undef :finished_b
215
+ end
216
+ simple
217
+ end
218
+
219
+ def balanced_callback
220
+ cb = Object.new
221
+ class << cb
222
+ attr_reader :result
223
+
224
+ def reset
225
+ @result = []
226
+ end
227
+
228
+ def match(event)
229
+ @result << [ "=", event.old_position, event.new_position ]
230
+ end
231
+
232
+ def discard_a(event)
233
+ @result << [ "<", event.old_position, event.new_position ]
234
+ end
235
+
236
+ def discard_b(event)
237
+ @result << [ ">", event.old_position, event.new_position ]
238
+ end
239
+
240
+ def change(event)
241
+ @result << [ "!", event.old_position, event.new_position ]
242
+ end
243
+ end
244
+ cb.reset
245
+ cb
246
+ end
247
+
248
+ def balanced_callback_no_change
249
+ balanced = balanced_callback
250
+ class << balanced
251
+ undef :change
252
+ end
253
+ balanced
254
+ end
255
+
256
+ module Matchers
257
+ extend RSpec::Matchers::DSL
258
+
259
+ matcher :be_nil_or_match_values do |ii, s1, s2|
260
+ match do |ee|
261
+ ee.should satisfy { |vee| vee.nil? || s1[ii] == s2[ee] }
262
+ end
263
+ end
264
+
265
+ matcher :correctly_map_sequence do |s1|
266
+ match do |actual|
267
+ actual.each_with_index { |ee, ii|
268
+ ee.should be_nil_or_match_values(ii, s1, @s2)
269
+ }
270
+ end
271
+
272
+ chain :to_other_sequence do |s2|
273
+ @s2 = s2
274
+ end
275
+ end
276
+ end
277
+ end
278
+
279
+ RSpec.configure do |conf|
280
+ conf.include Diff::LCS::SpecHelper
281
+ conf.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
282
+ end
283
+
284
+ # vim: ft=ruby
@@ -0,0 +1,286 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe "Diff::LCS.traverse_balanced" do
6
+ include Diff::LCS::SpecHelper::Matchers
7
+
8
+ shared_examples "with a #change callback" do |s1, s2, result|
9
+ it "should traverse s1 -> s2 correctly" do
10
+ traversal = balanced_traversal(s1, s2, :balanced_callback)
11
+ traversal.result.should == result
12
+ end
13
+
14
+ it "should traverse s2 -> s1 correctly" do
15
+ traversal = balanced_traversal(s2, s1, :balanced_callback)
16
+ traversal.result.should == balanced_reverse(result)
17
+ end
18
+ end
19
+
20
+ shared_examples "without a #change callback" do |s1, s2, result|
21
+ it "should traverse s1 -> s2 correctly" do
22
+ traversal = balanced_traversal(s1, s2, :balanced_callback_no_change)
23
+ traversal.result.should == map_to_no_change(result)
24
+ end
25
+
26
+ it "should traverse s2 -> s1 correctly" do
27
+ traversal = balanced_traversal(s2, s1, :balanced_callback_no_change)
28
+ traversal.result.should == map_to_no_change(balanced_reverse(result))
29
+ end
30
+ end
31
+
32
+ describe "sequences %w(a b c) & %w(a x c)" do
33
+ s1 = %w(a b c)
34
+ s2 = %w(a x c)
35
+
36
+ result = [
37
+ [ '=', 0, 0 ],
38
+ [ '!', 1, 1 ],
39
+ [ '=', 2, 2 ]
40
+ ]
41
+
42
+ it_has_behavior "with a #change callback", s1, s2, result
43
+ it_has_behavior "without a #change callback", s1, s2, result
44
+ end
45
+
46
+ describe "sequences %w(a x y c) & %w(a v w c)" do
47
+ s1 = %w(a x y c)
48
+ s2 = %w(a v w c)
49
+
50
+ result = [
51
+ [ '=', 0, 0 ],
52
+ [ '!', 1, 1 ],
53
+ [ '!', 2, 2 ],
54
+ [ '=', 3, 3 ]
55
+ ]
56
+
57
+ it_has_behavior "with a #change callback", s1, s2, result
58
+ it_has_behavior "without a #change callback", s1, s2, result
59
+ end
60
+
61
+ describe "sequences %w(x y c) & %w(v w c)" do
62
+ s1 = %w(x y c)
63
+ s2 = %w(v w c)
64
+ result = [
65
+ [ '!', 0, 0 ],
66
+ [ '!', 1, 1 ],
67
+ [ '=', 2, 2 ]
68
+ ]
69
+
70
+ it_has_behavior "with a #change callback", s1, s2, result
71
+ it_has_behavior "without a #change callback", s1, s2, result
72
+ end
73
+
74
+ describe "sequences %w(a x y z) & %w(b v w)" do
75
+ s1 = %w(a x y z)
76
+ s2 = %w(b v w)
77
+ result = [
78
+ [ '!', 0, 0 ],
79
+ [ '!', 1, 1 ],
80
+ [ '!', 2, 2 ],
81
+ [ '<', 3, 3 ]
82
+ ]
83
+
84
+ it_has_behavior "with a #change callback", s1, s2, result
85
+ it_has_behavior "without a #change callback", s1, s2, result
86
+ end
87
+
88
+ describe "sequences %w(a z) & %w(a)" do
89
+ s1 = %w(a z)
90
+ s2 = %w(a)
91
+ result = [
92
+ [ '=', 0, 0 ],
93
+ [ '<', 1, 1 ]
94
+ ]
95
+
96
+ it_has_behavior "with a #change callback", s1, s2, result
97
+ it_has_behavior "without a #change callback", s1, s2, result
98
+ end
99
+
100
+ describe "sequences %w(z a) & %w(a)" do
101
+ s1 = %w(z a)
102
+ s2 = %w(a)
103
+ result = [
104
+ [ '<', 0, 0 ],
105
+ [ '=', 1, 0 ]
106
+ ]
107
+
108
+ it_has_behavior "with a #change callback", s1, s2, result
109
+ it_has_behavior "without a #change callback", s1, s2, result
110
+ end
111
+
112
+ describe "sequences %w(a b c) & %w(x y z)" do
113
+ s1 = %w(a b c)
114
+ s2 = %w(x y z)
115
+ result = [
116
+ [ '!', 0, 0 ],
117
+ [ '!', 1, 1 ],
118
+ [ '!', 2, 2 ]
119
+ ]
120
+
121
+ it_has_behavior "with a #change callback", s1, s2, result
122
+ it_has_behavior "without a #change callback", s1, s2, result
123
+ end
124
+
125
+ describe "sequences %w(abcd efgh ijkl mnoopqrstuvwxyz) & []" do
126
+ s1 = %w(abcd efgh ijkl mnopqrstuvwxyz)
127
+ s2 = []
128
+ result = [
129
+ [ '<', 0, 0 ],
130
+ [ '<', 1, 0 ],
131
+ [ '<', 2, 0 ],
132
+ [ '<', 3, 0 ]
133
+ ]
134
+
135
+ it_has_behavior "with a #change callback", s1, s2, result
136
+ it_has_behavior "without a #change callback", s1, s2, result
137
+ end
138
+
139
+ describe "strings %Q(a b c) & %Q(a x c)" do
140
+ s1 = %Q(a b c)
141
+ s2 = %Q(a x c)
142
+
143
+ result = [
144
+ [ '=', 0, 0 ],
145
+ [ '=', 1, 1 ],
146
+ [ '!', 2, 2 ],
147
+ [ '=', 3, 3 ],
148
+ [ '=', 4, 4 ]
149
+ ]
150
+
151
+ it_has_behavior "with a #change callback", s1, s2, result
152
+ it_has_behavior "without a #change callback", s1, s2, result
153
+ end
154
+
155
+ describe "strings %Q(a x y c) & %Q(a v w c)" do
156
+ s1 = %Q(a x y c)
157
+ s2 = %Q(a v w c)
158
+
159
+ result = [
160
+ [ '=', 0, 0 ],
161
+ [ '=', 1, 1 ],
162
+ [ '!', 2, 2 ],
163
+ [ '=', 3, 3 ],
164
+ [ '!', 4, 4 ],
165
+ [ '=', 5, 5 ],
166
+ [ '=', 6, 6 ]
167
+ ]
168
+
169
+ it_has_behavior "with a #change callback", s1, s2, result
170
+ it_has_behavior "without a #change callback", s1, s2, result
171
+ end
172
+
173
+ describe "strings %Q(x y c) & %Q(v w c)" do
174
+ s1 = %Q(x y c)
175
+ s2 = %Q(v w c)
176
+ result = [
177
+ [ '!', 0, 0 ],
178
+ [ '=', 1, 1 ],
179
+ [ '!', 2, 2 ],
180
+ [ '=', 3, 3 ],
181
+ [ '=', 4, 4 ]
182
+ ]
183
+
184
+ it_has_behavior "with a #change callback", s1, s2, result
185
+ it_has_behavior "without a #change callback", s1, s2, result
186
+ end
187
+
188
+ describe "strings %Q(a x y z) & %Q(b v w)" do
189
+ s1 = %Q(a x y z)
190
+ s2 = %Q(b v w)
191
+ result = [
192
+ [ '!', 0, 0 ],
193
+ [ '=', 1, 1 ],
194
+ [ '!', 2, 2 ],
195
+ [ '=', 3, 3 ],
196
+ [ '!', 4, 4 ],
197
+ [ '<', 5, 5 ],
198
+ [ '<', 6, 5 ]
199
+ ]
200
+
201
+ it_has_behavior "with a #change callback", s1, s2, result
202
+ it_has_behavior "without a #change callback", s1, s2, result
203
+ end
204
+
205
+ describe "strings %Q(a z) & %Q(a)" do
206
+ s1 = %Q(a z)
207
+ s2 = %Q(a)
208
+ result = [
209
+ [ '=', 0, 0 ],
210
+ [ '<', 1, 1 ],
211
+ [ '<', 2, 1 ]
212
+ ]
213
+
214
+ it_has_behavior "with a #change callback", s1, s2, result
215
+ it_has_behavior "without a #change callback", s1, s2, result
216
+ end
217
+
218
+ describe "strings %Q(z a) & %Q(a)" do
219
+ s1 = %Q(z a)
220
+ s2 = %Q(a)
221
+ result = [
222
+ [ '<', 0, 0 ],
223
+ [ '<', 1, 0 ],
224
+ [ '=', 2, 0 ]
225
+ ]
226
+
227
+ it_has_behavior "with a #change callback", s1, s2, result
228
+ it_has_behavior "without a #change callback", s1, s2, result
229
+ end
230
+
231
+ describe "strings %Q(a b c) & %Q(x y z)" do
232
+ s1 = %Q(a b c)
233
+ s2 = %Q(x y z)
234
+ result = [
235
+ [ '!', 0, 0 ],
236
+ [ '=', 1, 1 ],
237
+ [ '!', 2, 2 ],
238
+ [ '=', 3, 3 ],
239
+ [ '!', 4, 4 ]
240
+ ]
241
+
242
+ it_has_behavior "with a #change callback", s1, s2, result
243
+ it_has_behavior "without a #change callback", s1, s2, result
244
+ end
245
+
246
+ describe "strings %Q(abcd efgh ijkl mnopqrstuvwxyz) & %Q()" do
247
+ s1 = %Q(abcd efgh ijkl mnopqrstuvwxyz)
248
+ s2 = ""
249
+ result = [
250
+ [ '<', 0, 0 ],
251
+ [ '<', 1, 0 ],
252
+ [ '<', 2, 0 ],
253
+ [ '<', 3, 0 ],
254
+ [ '<', 4, 0 ],
255
+ [ '<', 5, 0 ],
256
+ [ '<', 6, 0 ],
257
+ [ '<', 7, 0 ],
258
+ [ '<', 8, 0 ],
259
+ [ '<', 9, 0 ],
260
+ [ '<', 10, 0 ],
261
+ [ '<', 11, 0 ],
262
+ [ '<', 12, 0 ],
263
+ [ '<', 13, 0 ],
264
+ [ '<', 14, 0 ],
265
+ [ '<', 15, 0 ],
266
+ [ '<', 16, 0 ],
267
+ [ '<', 17, 0 ],
268
+ [ '<', 18, 0 ],
269
+ [ '<', 19, 0 ],
270
+ [ '<', 20, 0 ],
271
+ [ '<', 21, 0 ],
272
+ [ '<', 22, 0 ],
273
+ [ '<', 23, 0 ],
274
+ [ '<', 24, 0 ],
275
+ [ '<', 25, 0 ],
276
+ [ '<', 26, 0 ],
277
+ [ '<', 27, 0 ],
278
+ [ '<', 28, 0 ],
279
+ ]
280
+
281
+ it_has_behavior "with a #change callback", s1, s2, result
282
+ it_has_behavior "without a #change callback", s1, s2, result
283
+ end
284
+ end
285
+
286
+ # vim: ft=ruby