docdiff 0.6.4 → 0.6.6

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