docdiff 0.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 (73) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +7 -0
  3. data/Gemfile +17 -0
  4. data/Guardfile +8 -0
  5. data/Makefile +108 -0
  6. data/Rakefile +17 -0
  7. data/bin/docdiff +179 -0
  8. data/devutil/JIS0208.TXT +6952 -0
  9. data/devutil/char_by_charclass.rb +23 -0
  10. data/devutil/charclass_by_char.rb +21 -0
  11. data/devutil/jis0208.rb +343 -0
  12. data/devutil/testjis0208.rb +38 -0
  13. data/docdiff.conf.example +22 -0
  14. data/docdiff.gemspec +23 -0
  15. data/docdiffwebui.cgi +176 -0
  16. data/docdiffwebui.html +123 -0
  17. data/img/docdiff-screenshot-format-html-digest-firefox.png +0 -0
  18. data/img/docdiff-screenshot-format-html-firefox.png +0 -0
  19. data/img/docdiff-screenshot-format-tty-cmdexe-en.png +0 -0
  20. data/img/docdiff-screenshot-format-tty-cmdexe-ja.png +0 -0
  21. data/img/docdiff-screenshot-format-tty-rxvtunicode-en.png +0 -0
  22. data/img/docdiff-screenshot-format-tty-rxvtunicode-ja.png +0 -0
  23. data/img/docdiff-screenshot-format-tty-xterm-en.png +0 -0
  24. data/img/docdiff-screenshot-format-tty-xterm-ja.png +0 -0
  25. data/img/docdiff-screenshot-resolution-linewordchar-xterm.png +0 -0
  26. data/index.html +181 -0
  27. data/langfilter.rb +14 -0
  28. data/lib/doc_diff.rb +170 -0
  29. data/lib/docdiff.rb +7 -0
  30. data/lib/docdiff/charstring.rb +579 -0
  31. data/lib/docdiff/diff.rb +217 -0
  32. data/lib/docdiff/diff/contours.rb +382 -0
  33. data/lib/docdiff/diff/editscript.rb +148 -0
  34. data/lib/docdiff/diff/rcsdiff.rb +107 -0
  35. data/lib/docdiff/diff/shortestpath.rb +93 -0
  36. data/lib/docdiff/diff/speculative.rb +40 -0
  37. data/lib/docdiff/diff/subsequence.rb +39 -0
  38. data/lib/docdiff/diff/unidiff.rb +124 -0
  39. data/lib/docdiff/difference.rb +92 -0
  40. data/lib/docdiff/document.rb +127 -0
  41. data/lib/docdiff/encoding/en_ascii.rb +97 -0
  42. data/lib/docdiff/encoding/ja_eucjp.rb +269 -0
  43. data/lib/docdiff/encoding/ja_sjis.rb +260 -0
  44. data/lib/docdiff/encoding/ja_utf8.rb +6974 -0
  45. data/lib/docdiff/version.rb +3 -0
  46. data/lib/docdiff/view.rb +476 -0
  47. data/lib/viewdiff.rb +375 -0
  48. data/readme.html +713 -0
  49. data/sample/01.en.ascii.cr +1 -0
  50. data/sample/01.en.ascii.crlf +2 -0
  51. data/sample/01.en.ascii.lf +2 -0
  52. data/sample/01.ja.eucjp.lf +2 -0
  53. data/sample/01.ja.sjis.cr +1 -0
  54. data/sample/01.ja.sjis.crlf +2 -0
  55. data/sample/01.ja.utf8.crlf +2 -0
  56. data/sample/02.en.ascii.cr +1 -0
  57. data/sample/02.en.ascii.crlf +2 -0
  58. data/sample/02.en.ascii.lf +2 -0
  59. data/sample/02.ja.eucjp.lf +2 -0
  60. data/sample/02.ja.sjis.cr +1 -0
  61. data/sample/02.ja.sjis.crlf +2 -0
  62. data/sample/02.ja.utf8.crlf +2 -0
  63. data/sample/humpty_dumpty01.ascii.lf +4 -0
  64. data/sample/humpty_dumpty02.ascii.lf +4 -0
  65. data/test/charstring_test.rb +1008 -0
  66. data/test/diff_test.rb +36 -0
  67. data/test/difference_test.rb +64 -0
  68. data/test/docdiff_test.rb +193 -0
  69. data/test/document_test.rb +626 -0
  70. data/test/test_helper.rb +7 -0
  71. data/test/view_test.rb +570 -0
  72. data/test/viewdiff_test.rb +908 -0
  73. metadata +129 -0
@@ -0,0 +1,3 @@
1
+ module Docdiff
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,476 @@
1
+ #!/usr/bin/ruby
2
+
3
+ class String
4
+ def scan_lines(eol)
5
+ case eol
6
+ when nil then scan(/\A.*\Z/m)
7
+ when "CR" then scan(/.*?\r|[^\r]+\Z/m)
8
+ when "LF" then scan(/.*?\n|[^\n]+\Z/m)
9
+ when "CRLF" then scan(/.*?\r\n|.+\Z/m)
10
+ else raise "#{eol} is not supported.\n"
11
+ end
12
+ end
13
+ def scan_eols(eol)
14
+ case eol
15
+ when nil then []
16
+ when "CR" then scan(/\r/m)
17
+ when "LF" then scan(/\n/m)
18
+ when "CRLF" then scan(/\r\n/m)
19
+ else raise "#{eol} is not supported.\n"
20
+ end
21
+ end
22
+ end
23
+
24
+ class View
25
+
26
+ # EOL_CHARS_PAT = Regexp.new(/\r\n|\r(?!\n)|(?:\A|[^\r])\n/m)
27
+
28
+ def initialize(difference, encoding, eol)
29
+ @difference = difference
30
+ @encoding = encoding
31
+ @eol = eol
32
+ @eol_char = {'CR'=>"\r", 'LF'=>"\n", 'CRLF'=>"\r\n"}[@eol]
33
+ # if CharString::EOLChars[@eol]
34
+ # @eol_char = CharString::EOLChars[@eol].eol_char
35
+ # else
36
+ # @eol_char = nil
37
+ # end
38
+ end
39
+
40
+ def difference_whole()
41
+ @difference
42
+ end
43
+
44
+ def difference_digest()
45
+ #
46
+ end
47
+
48
+ def escape_inside(str, tags)
49
+ str.gsub(tags[:inside_escape_pat]){|m| tags[:inside_escape_dic][m]}
50
+ end
51
+ def escape_outside(str, tags)
52
+ str.gsub(tags[:outside_escape_pat]){|m| tags[:outside_escape_dic][m]}
53
+ end
54
+
55
+ def apply_style(tags, headfoot = true)
56
+ result = []
57
+ @difference.each{|block|
58
+ operation = block.first
59
+ if block_given?
60
+ src = yield((block[1] || []).join)
61
+ tgt = yield((block[1] || []).join)
62
+ else
63
+ src = (block[1] || []).join
64
+ tgt = (block[2] || []).join
65
+ end
66
+ case operation
67
+ when :common_elt_elt
68
+ result << (tags[:start_common] + escape_outside(src, tags) + tags[:end_common])
69
+ when :change_elt
70
+ result << (tags[:start_before_change] + escape_inside(src, tags) + tags[:end_before_change] +
71
+ tags[:start_after_change] + escape_inside(tgt, tags) + tags[:end_after_change])
72
+ when :del_elt
73
+ result << (tags[:start_del] + escape_inside(src, tags) + tags[:end_del])
74
+ when :add_elt
75
+ result << (tags[:start_add] + escape_inside(tgt, tags) + tags[:end_add])
76
+ else
77
+ raise "invalid attribute: #{block.first}\n"
78
+ end
79
+ }
80
+ if headfoot == true
81
+ result = tags[:header] + result + tags[:footer]
82
+ end
83
+ result.delete_if{|elem|elem==''}
84
+ end
85
+
86
+ def encname_for_regexp(encname)
87
+ def ruby_m17n?
88
+ "".respond_to?(:force_encoding)
89
+ end
90
+ if ruby_m17n?
91
+ # in 1.9.x, encoding names are deprecated except for N (ASCII-8BIT (binary))
92
+ nil
93
+ else
94
+ # in 1.8.x, U|E|S|N are accepted
95
+ encname.sub(/US-ASCII/i, 'none')
96
+ end
97
+ end
98
+
99
+ CONTEXT_PRE_LENGTH = 32
100
+ CONTEXT_POST_LENGTH = 32
101
+ def apply_style_digest(tags, headfoot = true)
102
+ cxt_pre_pat = Regexp.new('.{0,'+"#{CONTEXT_PRE_LENGTH}"+'}\Z',
103
+ Regexp::MULTILINE, encname_for_regexp(@encoding))
104
+ cxt_post_pat = Regexp.new('\A.{0,'+"#{CONTEXT_POST_LENGTH}"+'}',
105
+ Regexp::MULTILINE, encname_for_regexp(@encoding))
106
+ display = (tags and tags[:display]) || 'inline'
107
+ result = []
108
+ d1l = doc1_line_number = 1
109
+ d2l = doc2_line_number = 1
110
+ @difference.each_with_index{|entry, i|
111
+ if block_given?
112
+ src = yield((entry[1] || []).join)
113
+ tgt = yield((entry[1] || []).join)
114
+ else
115
+ src = (entry[1] || []).join
116
+ tgt = (entry[2] || []).join
117
+ end
118
+ cxt_pre = if i == 0
119
+ "" # no pre context for the first entry
120
+ else
121
+ (@difference[i-1][1] || []).join.scan(cxt_pre_pat).join
122
+ end
123
+ cxt_post = if (i + 1) == @difference.size
124
+ "" # no post context for the last entry
125
+ else
126
+ (@difference[i+1][1] || []).join.scan(cxt_post_pat).join
127
+ end
128
+ # elements for an entry
129
+ e_head = Proc.new {|pos_str|
130
+ tags[:start_entry] + tags[:start_position] + pos_str + tags[:end_position]}
131
+ e_cxt_pre = tags[:start_prefix] + escape_outside(cxt_pre, tags) + tags[:end_prefix]
132
+ e_src = escape_inside(src, tags)
133
+ e_chg = tags[:start_before_change] + escape_inside(src, tags) + tags[:end_before_change] +
134
+ tags[:start_after_change] + escape_inside(tgt, tags) + tags[:end_after_change]
135
+ e_chgdel = tags[:start_before_change] + escape_inside(src, tags) + tags[:end_before_change]
136
+ e_chgadd = tags[:start_after_change] + escape_inside(tgt, tags) + tags[:end_after_change]
137
+ e_del = tags[:start_del] + escape_outside(src, tags) + tags[:end_del]
138
+ e_add = tags[:start_add] + escape_outside(tgt, tags) + tags[:end_add]
139
+ e_cxt_post = tags[:start_postfix] + escape_outside(cxt_post, tags) + tags[:end_postfix]
140
+ e_foot = tags[:end_entry] + (@eol_char||"")
141
+
142
+ span1 = source_lines_involved = src.scan_lines(@eol).size
143
+ span2 = target_lines_involved = tgt.scan_lines(@eol).size
144
+ pos_str = ""
145
+ case operation = entry.first
146
+ when :common_elt_elt
147
+ # skipping common part
148
+ when :change_elt
149
+ pos_str = "#{d1l}" + "#{if span1 > 1 then '-'+(d1l + span1 - 1).to_s; end}" +
150
+ ",#{d2l}" + "#{if span2 > 1 then '-'+(d2l + span2 - 1).to_s; end}"
151
+ case display
152
+ when 'inline'
153
+ result << (e_head.call(pos_str) + e_cxt_pre + e_chg + e_cxt_post + e_foot)
154
+ when 'multi'
155
+ result << (e_head.call(pos_str) + e_cxt_pre + e_chgdel + e_cxt_post +
156
+ e_cxt_pre + e_chgadd + e_cxt_post + e_foot)
157
+ else raise "Unsupported display type: #{display}"
158
+ end
159
+ when :del_elt
160
+ pos_str = "#{d1l}" + "#{if span1 > 1 then '-'+(d1l + span1 - 1).to_s; end}" +
161
+ ",(#{d2l})"
162
+ case display
163
+ when 'inline'
164
+ result << (e_head.call(pos_str) + e_cxt_pre + e_del + e_cxt_post + e_foot)
165
+ when 'multi'
166
+ result << (e_head.call(pos_str) + e_cxt_pre + e_src + e_cxt_post +
167
+ e_cxt_pre + e_del + e_cxt_post + e_foot)
168
+ else raise "Unsupported display type: #{display}"
169
+ end
170
+ when :add_elt
171
+ pos_str = "(#{d1l})" +
172
+ ",#{d2l}" + "#{if span2 > 1 then '-'+(d2l + span2 - 1).to_s; end}"
173
+ case display
174
+ when 'inline'
175
+ result << (e_head.call(pos_str) + e_cxt_pre + e_add + e_cxt_post + e_foot)
176
+ when 'multi'
177
+ result << (e_head.call(pos_str) + e_cxt_pre + e_src + e_cxt_post +
178
+ e_cxt_pre + e_add + e_cxt_post + e_foot)
179
+ else raise "Unsupported display type: #{display}"
180
+ end
181
+ else
182
+ raise "invalid attribute: #{block.first}\n"
183
+ end
184
+ d1l += src.scan_eols(@eol).size
185
+ d2l += tgt.scan_eols(@eol).size
186
+ }
187
+ result.unshift(tags[:start_digest_body])
188
+ result.push(tags[:end_digest_body])
189
+ result = tags[:header] + result + tags[:footer] if headfoot == true
190
+ result.delete_if{|elem| elem == ''}
191
+ end
192
+
193
+ def source_lines()
194
+ if @source_lines == nil
195
+ @source_lines = @difference.collect{|entry| entry[1]}.join.scan_lines(@eol)
196
+ end
197
+ @source_lines
198
+ end
199
+ def target_lines()
200
+ if @target_lines == nil
201
+ @target_lines = @difference.collect{|entry| entry[2]}.join.scan_lines(@eol)
202
+ end
203
+ @target_lines
204
+ end
205
+
206
+ # tty (terminal)
207
+ def tty_header()
208
+ []
209
+ end
210
+ def tty_footer()
211
+ []
212
+ end
213
+ TTYEscapeDic = {'ThisRandomString' => 'ThisRandomString'}
214
+ TTYEscapePat = /(\r\n|#{TTYEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
215
+ def tty_tags()
216
+ {:outside_escape_dic => TTYEscapeDic,
217
+ :outside_escape_pat => TTYEscapePat,
218
+ :inside_escape_dic => TTYEscapeDic,
219
+ :inside_escape_pat => TTYEscapePat,
220
+ :start_digest_body => "----#{@eol_char||''}",
221
+ :end_digest_body => '',
222
+ :start_entry => '',
223
+ :end_entry => "----",
224
+ :start_position => '',
225
+ :end_position => "#{@eol_char||''}",
226
+ :start_prefix => '',
227
+ :end_prefix => '',
228
+ :start_postfix => '',
229
+ :end_postfix => "#{@eol_char||''}",
230
+ :header => tty_header(),
231
+ :footer => tty_footer(),
232
+ :start_common => '',
233
+ :end_common => '',
234
+ :start_del => "\033[7;4;31m", # Inverted, Underlined, Red
235
+ :end_del => "\033[0m",
236
+ :start_add => "\033[7;1;34m", # Inverted, Bold, Blue
237
+ :end_add => "\033[0m",
238
+ :start_before_change => "\033[7;4;33m", # Inverted, Underlined, Yellow
239
+ :end_before_change => "\033[0m",
240
+ :start_after_change => "\033[7;1;32m", # Inverted, Bold, Green
241
+ :end_after_change => "\033[0m"}
242
+ end
243
+ def to_tty(overriding_opts = nil, headfoot = true) # color escape sequence
244
+ tags = tty_tags()
245
+ tags.update(overriding_opts) if overriding_opts
246
+ apply_style(tags, headfoot)
247
+ end
248
+ def to_tty_digest(overriding_opts = nil, headfoot = true)
249
+ tags = tty_tags
250
+ tags.update(overriding_opts) if overriding_opts
251
+ apply_style_digest(tags, headfoot)
252
+ end
253
+
254
+ # HTML (XHTML)
255
+ def html_header()
256
+ ["<?xml version=\"1.0\" encoding=\"#{@encoding||''}\"?>#{@eol_char||''}",
257
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"#{@eol_char||''}",
258
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">#{@eol_char||''}",
259
+ "<html><head>#{@eol_char||''}",
260
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=#{@encoding||''}\" />#{@eol_char||''}",
261
+ "<title>Difference</title>#{@eol_char||''}",
262
+ "<style type=\"text/css\">#{@eol_char||''}" +
263
+ " body {font-family: monospace;}#{@eol_char||''}" +
264
+ " span.del {background: hotpink; border: thin inset;}#{@eol_char||''}" +
265
+ " span.add {background: deepskyblue; font-weight: bolder; border: thin outset;}#{@eol_char||''}" +
266
+ " span.before-change {background: yellow; border: thin inset;}#{@eol_char||''}" +
267
+ " span.after-change {background: lime; font-weight: bolder; border: thin outset;}#{@eol_char||''}" +
268
+ " li.entry .position {font-weight: bolder; margin-top: 0em; margin-bottom: 0em; padding-top: 0.5em; padding-bottom: 0em;}#{@eol_char||''}" +
269
+ " li.entry .body {margin-top: 0em; margin-bottom: 0em; padding-top: 0em; padding-bottom: 0.5em;}#{@eol_char||''}" +
270
+ " li.entry {border-top: thin solid gray;}#{@eol_char||''}" +
271
+ "</style>#{@eol_char||''}",
272
+ "</head><body><div>#{@eol_char||''}"]
273
+ end
274
+ def html_footer()
275
+ [(@eol_char||"") + '</div></body></html>' + (@eol_char||"")]
276
+ end
277
+ HTMLEscapeDic = {'<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', ' '=>'&nbsp;&nbsp;',
278
+ "\r\n" => "<br />\r\n", "\r" => "<br />\r", "\n" => "<br />\n"}
279
+ HTMLEscapePat = /(\r\n|#{HTMLEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
280
+ def html_tags()
281
+ {:outside_escape_dic => HTMLEscapeDic,
282
+ :outside_escape_pat => HTMLEscapePat,
283
+ :inside_escape_dic => HTMLEscapeDic,
284
+ :inside_escape_pat => HTMLEscapePat,
285
+ :start_digest_body => '<ul>',
286
+ :end_digest_body => '</ul>',
287
+ :start_entry => '<li class="entry">',
288
+ :end_entry => '</blockquote></li>',
289
+ :start_position => '<p class="position">',
290
+ :end_position => '</p><blockquote class="body">',
291
+ :start_prefix => '<p class="body">',
292
+ :end_prefix => '',
293
+ :start_postfix => '',
294
+ :end_postfix => '</p>',
295
+ :header => html_header(),
296
+ :footer => html_footer(),
297
+ :start_common => '<span class="common">',
298
+ :end_common => '</span>',
299
+ :start_del => '<span class="del"><del>',
300
+ :end_del => '</del></span>',
301
+ :start_add => '<span class="add"><ins>',
302
+ :end_add => '</ins></span>',
303
+ :start_before_change => '<span class="before-change"><del>',
304
+ :end_before_change => '</del></span>',
305
+ :start_after_change => '<span class="after-change"><ins>',
306
+ :end_after_change => '</ins></span>'}
307
+ end
308
+ def to_html(overriding_opts = nil, headfoot = true)
309
+ tags = html_tags()
310
+ tags.update(overriding_opts) if overriding_opts
311
+ apply_style(tags, headfoot)
312
+ end
313
+ def to_html_digest(overriding_opts = nil, headfoot = true)
314
+ tags = html_tags()
315
+ tags.update(overriding_opts) if overriding_opts
316
+ apply_style_digest(tags, headfoot)
317
+ end
318
+
319
+ # Manued
320
+ def manued_header()
321
+ ["defparentheses [ ]" + (@eol_char||"\n"),
322
+ "defdelete /" + (@eol_char||"\n"),
323
+ "defswap |" + (@eol_char||"\n"),
324
+ "defcomment ;" + (@eol_char||"\n"),
325
+ "defescape ~" + (@eol_char||"\n"),
326
+ "deforder newer-last" + (@eol_char||"\n"),
327
+ "defversion 0.9.5" + (@eol_char||"\n")]
328
+ end
329
+ def manued_footer()
330
+ []
331
+ end
332
+ ManuedInsideEscapeDic = {'~'=>'~~', '/'=>'~/', '['=>'~[', ']'=>'~]', ';'=>'~;'}
333
+ ManuedInsideEscapePat = /(#{ManuedInsideEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
334
+ ManuedOutsideEscapeDic = {'~'=>'~~', '['=>'~['}
335
+ ManuedOutsideEscapePat = /(#{ManuedOutsideEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
336
+ def manued_tags()
337
+ {:inside_escape_dic => ManuedInsideEscapeDic,
338
+ :inside_escape_pat => ManuedInsideEscapePat,
339
+ :outside_escape_dic => ManuedOutsideEscapeDic,
340
+ :outside_escape_pat => ManuedOutsideEscapePat,
341
+ :start_digest_body => "----#{@eol_char||''}",
342
+ :end_digest_body => '',
343
+ :start_entry => '',
344
+ :end_entry => "----",
345
+ :start_position => '',
346
+ :end_position => "#{@eol_char||''}",
347
+ :start_prefix => '',
348
+ :end_prefix => '',
349
+ :start_postfix => '',
350
+ :end_postfix => "#{@eol_char||''}",
351
+ :header => manued_header(),
352
+ :footer => manued_footer(),
353
+ :start_common => '',
354
+ :end_common => '',
355
+ :start_del => '[',
356
+ :end_del => '/]',
357
+ :start_add => '[/',
358
+ :end_add => ']',
359
+ :start_before_change => '[',
360
+ :end_before_change => '/',
361
+ :start_after_change => '',
362
+ :end_after_change => ']'
363
+ }
364
+ end
365
+ def to_manued(overriding_opts = nil, headfoot = true) # [ / ; ]
366
+ tags = manued_tags()
367
+ tags.update(overriding_opts) if overriding_opts
368
+ apply_style(tags, headfoot)
369
+ end
370
+ def to_manued_digest(overriding_opts = nil, headfoot = true) # [ / ; ]
371
+ tags = manued_tags()
372
+ # manued specific kludge: change should be [a/b] in inline, [a/][/b] in multi
373
+ display = (overriding_opts and overriding_opts[:display]) || 'inline'
374
+ if display == 'multi'
375
+ tags.update({:end_before_change => '/]', :start_after_change => '[/'})
376
+ end
377
+ tags.update(overriding_opts) if overriding_opts
378
+ apply_style_digest(tags, headfoot)
379
+ end
380
+
381
+ # wdiff-like
382
+ def wdiff_header()
383
+ []
384
+ end
385
+ def wdiff_footer()
386
+ []
387
+ end
388
+ WDIFFEscapeDic = {'ThisRandomString' => 'ThisRandomString'}
389
+ WDIFFEscapePat = /(\r\n|#{WDIFFEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
390
+ def wdiff_tags()
391
+ {:outside_escape_dic => WDIFFEscapeDic,
392
+ :outside_escape_pat => WDIFFEscapePat,
393
+ :inside_escape_dic => WDIFFEscapeDic,
394
+ :inside_escape_pat => WDIFFEscapePat,
395
+ :start_digest_body => "----#{@eol_char||''}",
396
+ :end_digest_body => '',
397
+ :start_entry => '',
398
+ :end_entry => "----",
399
+ :start_position => '',
400
+ :end_position => "#{@eol_char||''}",
401
+ :start_prefix => '',
402
+ :end_prefix => '',
403
+ :start_postfix => '',
404
+ :end_postfix => "#{@eol_char||''}",
405
+ :header => wdiff_header(),
406
+ :footer => wdiff_footer(),
407
+ :start_common => '',
408
+ :end_common => '',
409
+ :start_del => '[-',
410
+ :end_del => '-]',
411
+ :start_add => '{+',
412
+ :end_add => '+}',
413
+ :start_before_change => '[-',
414
+ :end_before_change => '-]',
415
+ :start_after_change => '{+',
416
+ :end_after_change => '+}'}
417
+ end
418
+ def to_wdiff(overriding_opts = nil, headfoot = true)
419
+ tags = wdiff_tags()
420
+ tags.update(overriding_opts) if overriding_opts
421
+ apply_style(tags)
422
+ end
423
+ def to_wdiff_digest(overriding_opts = nil, headfoot = true)
424
+ tags = wdiff_tags()
425
+ tags.update(overriding_opts) if overriding_opts
426
+ apply_style_digest(tags, headfoot)
427
+ end
428
+
429
+ # user defined markup
430
+ def user_header(); []; end
431
+ def user_footer(); []; end
432
+ UserEscapeDic = {'ThisRandomString' => 'ThisRandomString'}
433
+ UserEscapePat = /(\r\n|#{UserEscapeDic.keys.collect{|k|Regexp.quote(k)}.join('|')})/m
434
+ def user_tags()
435
+ {:outside_escape_dic => UserEscapeDic,
436
+ :outside_escape_pat => UserEscapePat,
437
+ :inside_escape_dic => UserEscapeDic,
438
+ :inside_escape_pat => UserEscapePat,
439
+ :start_digest_body => '',
440
+ :end_digest_body => '',
441
+ :start_entry => '',
442
+ :end_entry => '',
443
+ :start_position => '',
444
+ :end_position => ' ',
445
+ :start_prefix => '',
446
+ :end_prefix => '',
447
+ :start_postfix => '',
448
+ :end_postfix => '',
449
+ :header => user_header(),
450
+ :footer => user_footer(),
451
+ :start_common => '',
452
+ :end_common => '',
453
+ :start_del => '',
454
+ :end_del => '',
455
+ :start_add => '',
456
+ :end_add => '',
457
+ :start_before_change => '',
458
+ :end_before_change => '',
459
+ :start_after_change => '',
460
+ :end_after_change => ''}
461
+ end
462
+ def to_user(overriding_opts = nil, headfoot = true)
463
+ tags = user_tags()
464
+ tags.update(overriding_opts) if overriding_opts
465
+ apply_style(tags, headfoot)
466
+ end
467
+ def to_user_digest(overriding_opts = nil, headfoot = true)
468
+ tags = user_tags()
469
+ tags.update(overriding_opts) if overriding_opts
470
+ apply_style_digest(tags, headfoot)
471
+ end
472
+
473
+ def to_debug()
474
+ end
475
+
476
+ end