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