1
1
#!/usr/bin/env ruby
2
2
# encoding: utf-8
3
3
4
- require 'ydocx'
4
+ require 'ydocx/builder '
5
5
require 'diff/lcs'
6
6
7
7
module YDocx
8
8
class Differ
9
+ Block = Struct . new ( :start_line , :type , :lines )
10
+
9
11
def initialize
10
12
@cur_change_id = 1
11
13
end
@@ -137,47 +139,48 @@ def get_paragraph_diff(p1, p2, result)
137
139
chunks [ i ] . each_with_index do |chunk , j |
138
140
if change_id [ i ] [ j ]
139
141
if change_id [ i ] [ j ] >= 1
140
- group . class = ( sprintf 'modify modify%d' , change_id [ i ] [ j ] )
142
+ group . css_class = ( sprintf 'modify modify- %d' , change_id [ i ] [ j ] )
141
143
elsif i == 0
142
- group . class = 'delete'
144
+ group . css_class = 'delete'
143
145
else
144
- group . class = 'add'
146
+ group . css_class = 'add'
145
147
end
146
148
if chunk == [ Run . new ( "\n " ) ]
147
149
group . runs << Run . new ( "↵\n " )
148
150
else
149
151
group . runs += chunk
150
152
end
151
153
else
152
- p . groups << group unless group . runs . empty?
154
+ p . runs << group unless group . runs . empty?
153
155
group = RunGroup . new
154
- p . groups << RunGroup . new ( chunk )
156
+ p . runs += chunk
155
157
end
156
158
end
157
- p . groups << group unless group . runs . empty?
158
- result [ i ] . blocks << p
159
+ p . runs << group unless group . runs . empty?
160
+ p . merge_runs
161
+ result [ i ] << p
159
162
end
160
163
end
161
164
def get_table_diff ( t1 , t2 , result )
162
165
tables = [ Table . new , Table . new ]
163
166
get_detail_blocks ( t1 . rows , t2 . rows ) . each do |rblock |
164
167
if rblock [ 0 ] . empty?
165
- rblock [ 1 ] . map { |r | r . cells . map { |c | c . class = 'add' } }
168
+ rblock [ 1 ] . map { |r | r . cells . map { |c | c . css_class = 'add' } }
166
169
tables [ 1 ] . rows += rblock [ 1 ]
167
170
elsif rblock [ 1 ] . empty?
168
- rblock [ 0 ] . map { |r | r . cells . map { |c | c . class = 'delete' } }
171
+ rblock [ 0 ] . map { |r | r . cells . map { |c | c . css_class = 'delete' } }
169
172
tables [ 0 ] . rows += rblock [ 0 ]
170
173
else # should be 1 row in each
171
174
change_id = get_diff_change_array ( rblock [ 0 ] . first . cells , rblock [ 1 ] . first . cells )
172
175
for i in 0 ..1
173
176
rblock [ i ] . first . cells . each_with_index do |cell , j |
174
177
if change_id [ i ] [ j ]
175
178
if change_id [ i ] [ j ] >= 1
176
- cell . class = ( sprintf 'modify modify%d' , change_id [ i ] [ j ] )
179
+ cell . css_class = ( sprintf 'modify modify- %d' , change_id [ i ] [ j ] )
177
180
elsif i == 0
178
- cell . class = 'delete'
181
+ cell . css_class = 'delete'
179
182
else
180
- cell . class = 'add'
183
+ cell . css_class = 'add'
181
184
end
182
185
end
183
186
end
@@ -186,18 +189,56 @@ def get_table_diff(t1, t2, result)
186
189
tables [ 1 ] . rows += rblock [ 1 ]
187
190
end
188
191
end
189
- result [ 0 ] . blocks << tables [ 0 ]
190
- result [ 1 ] . blocks << tables [ 1 ]
192
+ result [ 0 ] << tables [ 0 ]
193
+ result [ 1 ] << tables [ 1 ]
191
194
end
192
195
def diff ( doc1 , doc2 )
193
- blocks1 = doc1 . contents . blocks
194
- blocks2 = doc2 . contents . blocks
196
+ blocks1 = doc1 . blocks
197
+ blocks2 = doc2 . blocks
198
+ result = { :inline => [ [ ] , [ ] ] , :side => [ [ ] , [ ] ] }
199
+
200
+ pg = [ 1 , 1 ]
201
+ lblocks = [ ]
202
+ rblocks = [ ]
203
+ inline_blocks = [ ]
204
+ Diff ::LCS . sdiff ( blocks1 , blocks2 ) . each do |change |
205
+ if change . action == '='
206
+ inline_blocks << [ lblocks . dup , rblocks . dup ] unless lblocks . empty? && rblocks . empty?
207
+ inline_blocks << [ [ blocks1 [ change . old_position ] ] , [ blocks2 [ change . new_position ] ] ]
208
+ lblocks = [ ]
209
+ rblocks = [ ]
210
+ else
211
+ lblocks << blocks1 [ change . old_position ] unless change . old_element . nil?
212
+ rblocks << blocks2 [ change . new_position ] unless change . new_element . nil?
213
+ end
214
+ end
215
+ inline_blocks << [ lblocks . dup , rblocks . dup ] unless lblocks . empty? && rblocks . empty?
216
+ inline_blocks . each do |blocks |
217
+ html_blocks = blocks . map do |block |
218
+ block . map { |b | Builder . build_html ( b ) }
219
+ end
220
+ if blocks [ 0 ] == blocks [ 1 ]
221
+ result [ :inline ] [ 0 ] << Block . new ( pg [ 0 ] , '=' , html_blocks [ 0 ] )
222
+ result [ :inline ] [ 1 ] << Block . new ( pg [ 1 ] , '=' , html_blocks [ 1 ] )
223
+ pg [ 0 ] += html_blocks [ 0 ] . length
224
+ pg [ 1 ] += html_blocks [ 1 ] . length
225
+ else
226
+ unless blocks [ 0 ] . empty?
227
+ result [ :inline ] [ 0 ] << Block . new ( pg [ 0 ] , '-' , html_blocks [ 0 ] )
228
+ result [ :inline ] [ 1 ] << nil
229
+ pg [ 0 ] += html_blocks [ 0 ] . length
230
+ end
231
+ unless blocks [ 1 ] . empty?
232
+ result [ :inline ] [ 0 ] << nil
233
+ result [ :inline ] [ 1 ] << Block . new ( pg [ 1 ] , '+' , html_blocks [ 1 ] )
234
+ pg [ 1 ] += html_blocks [ 1 ] . length
235
+ end
236
+ end
237
+ end
195
238
196
- puts 'Extracting text...'
197
239
text1 = blocks1 . map { |b | b . get_chunks . map ( &method ( :get_text ) ) }
198
240
text2 = blocks2 . map { |b | b . get_chunks . map ( &method ( :get_text ) ) }
199
241
200
- puts 'Computing paragraph diffs...'
201
242
lblocks = [ ]
202
243
rblocks = [ ]
203
244
diff_blocks = [ ]
@@ -214,45 +255,44 @@ def diff(doc1, doc2)
214
255
end
215
256
diff_blocks << [ lblocks . dup , rblocks . dup ] unless lblocks . empty? && rblocks . empty?
216
257
217
- puts 'Computing block diffs...'
218
- table = Table . new
258
+ pg = [ 1 , 1 ]
219
259
diff_blocks . each do |dblock |
220
260
get_detail_blocks ( dblock [ 0 ] , dblock [ 1 ] ) . each do |block |
221
- row = Row . new
222
- row . cells = [ Cell . new , Cell . new ]
261
+ type = [ '=' , '=' ]
262
+ blocks = [ [ ] , [ ] ]
223
263
if block [ 0 ] . empty?
224
- row . cells [ 1 ] . class = 'add'
225
- row . cells [ 1 ] . blocks = block [ 1 ]
264
+ blocks [ 1 ] = block [ 1 ]
265
+ type [ 1 ] = '+'
226
266
elsif block [ 1 ] . empty?
227
- row . cells [ 0 ] . class = 'delete'
228
- row . cells [ 0 ] . blocks = block [ 0 ]
229
- elsif block [ 0 ] != block [ 1 ] # should only be 1 block in each
230
- row . cells [ 0 ] . class = row . cells [ 1 ] . class = 'modify'
267
+ blocks [ 0 ] = block [ 0 ]
268
+ type [ 0 ] = '-'
269
+ elsif block [ 0 ] != block [ 1 ]
270
+ # Each block should only contain 1 element
271
+ type = [ '!' , '!' ]
231
272
if block [ 0 ] . first . is_a? Paragraph
232
- get_paragraph_diff ( block [ 0 ] . first , block [ 1 ] . first , row . cells )
273
+ get_paragraph_diff ( block [ 0 ] . first , block [ 1 ] . first , blocks )
233
274
else
234
- get_table_diff ( block [ 0 ] . first , block [ 1 ] . first , row . cells )
275
+ get_table_diff ( block [ 0 ] . first , block [ 1 ] . first , blocks )
235
276
end
236
277
else
237
- row . cells [ 0 ] . blocks = block [ 0 ]
238
- row . cells [ 1 ] . blocks = block [ 1 ]
278
+ blocks [ 0 ] = block [ 0 ]
279
+ blocks [ 1 ] = block [ 1 ]
280
+ end
281
+ blocks = blocks . map do |block |
282
+ block . map { |b | Builder . build_html ( b ) }
283
+ end
284
+ for i in 0 ..1
285
+ if blocks [ i ] . empty?
286
+ result [ :side ] [ i ] << nil
287
+ else
288
+ result [ :side ] [ i ] << Block . new ( pg [ i ] , type [ i ] , blocks [ i ] )
289
+ pg [ i ] += blocks [ i ] . length
290
+ end
239
291
end
240
- table . rows << row
241
- end
242
- end
243
-
244
- [ doc1 , doc2 ] . each do |doc |
245
- if !doc . images . empty?
246
- doc . create_files
247
292
end
248
293
end
249
294
250
- html_doc = ParsedDocument . new
251
- html_doc . blocks << table
252
- builder = Builder . new ( html_doc )
253
- builder . title = 'Diff Results'
254
- builder . style = true
255
- builder . build_html
295
+ result
256
296
end
257
297
end
258
- end
298
+ end
0 commit comments