rbpar 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +58 -0
- data/bin/rbpar.rb +94 -0
- data/lib/rbpar_engine.rb +196 -0
- data/lib/rbpar_main.rb +68 -0
- data/lib/rbpar_paragraph.rb +344 -0
- data/test/rbpar_engine_test.rb +152 -0
- data/test/rbpar_main_test.rb +212 -0
- data/test/rbpar_paragraph_test.rb +305 -0
- data/test/rbpar_test.rb +11 -0
- metadata +54 -0
@@ -0,0 +1,344 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Paragraph is the main building block for the paragraph processing
|
4
|
+
# library. The paragraph keeps information about it's prefix and can
|
5
|
+
# split itself to subparagraphs and break its lines to optimal line
|
6
|
+
# widths.
|
7
|
+
#
|
8
|
+
# Copyright Ismo Puustinen 2007.
|
9
|
+
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
class Paragraph < Array
|
13
|
+
|
14
|
+
QUOTE_REGEXP_WITH_WHITESPACE = /\A(\s*>)+\s*/
|
15
|
+
QUOTE_REGEXP = /\A(\s*>)+/
|
16
|
+
|
17
|
+
attr_accessor :quote_prefix
|
18
|
+
|
19
|
+
def initialize(array = [])
|
20
|
+
super(array)
|
21
|
+
|
22
|
+
@quote_prefix = ""
|
23
|
+
@paragraphs = nil
|
24
|
+
@whitespace = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def prefix_library(original)
|
28
|
+
new_prefix = @prefix_db[original]
|
29
|
+
if new_prefix.nil?
|
30
|
+
return original
|
31
|
+
else
|
32
|
+
return new_prefix
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_paragraphs
|
37
|
+
|
38
|
+
if @paragraphs.nil?
|
39
|
+
@paragraphs = Array.new()
|
40
|
+
end
|
41
|
+
# start the recursion, results are collected to @paragraphs
|
42
|
+
tmp_paragraphs = get_sub_paragraphs(self)
|
43
|
+
@paragraphs
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_sub_paragraphs(paragraph)
|
48
|
+
|
49
|
+
# return the list of the sub-paragraphs
|
50
|
+
|
51
|
+
paragraph.find_quote_prefix()
|
52
|
+
paragraphs = paragraph.split_to_quoted()
|
53
|
+
|
54
|
+
# end recursion
|
55
|
+
if paragraphs.length == 1
|
56
|
+
# this is a depth-first search, thus we are processing the
|
57
|
+
# paragraphs in order.
|
58
|
+
@paragraphs << paragraph
|
59
|
+
return [paragraph]
|
60
|
+
end
|
61
|
+
|
62
|
+
paragraphs.each_with_index do |new_paragraph, i|
|
63
|
+
# new_paragraph.find_quote_prefix
|
64
|
+
paragraphs[i] = get_sub_paragraphs(new_paragraph)
|
65
|
+
end
|
66
|
+
|
67
|
+
return paragraphs
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def find_quote_prefix()
|
72
|
+
longest_match = ""
|
73
|
+
|
74
|
+
first = true
|
75
|
+
|
76
|
+
self.each do |line|
|
77
|
+
found = line.match(QUOTE_REGEXP_WITH_WHITESPACE)
|
78
|
+
@quote_prefix = "" ; @whitespace = 0 ; return "" unless found # no change
|
79
|
+
|
80
|
+
if first
|
81
|
+
# initialize
|
82
|
+
longest_match = $&
|
83
|
+
first = false
|
84
|
+
end
|
85
|
+
|
86
|
+
if $&.length < longest_match.length
|
87
|
+
longest_match = $&
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# puts "quote_prefix: '" + longest_match + "'"
|
92
|
+
# pp self
|
93
|
+
|
94
|
+
@quote_prefix = longest_match.rstrip
|
95
|
+
@whitespace = longest_match.size - @quote_prefix.size
|
96
|
+
# pp @quote_prefix
|
97
|
+
@quote_prefix
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
def quoted?(line)
|
102
|
+
return false unless line.length > @quote_prefix.length
|
103
|
+
|
104
|
+
# puts "line for comparison: '" + line[@quote_prefix.length..-1] + "'"
|
105
|
+
# puts "match: '" + (line[@quote_prefix.length..-1].match(QUOTE_REGEXP)).to_s + "'"
|
106
|
+
|
107
|
+
return !line[@quote_prefix.length..-1].match(QUOTE_REGEXP).nil?
|
108
|
+
end
|
109
|
+
|
110
|
+
def do_process?
|
111
|
+
# decide if this paragraph needs to be processed
|
112
|
+
#
|
113
|
+
# This is a problem case: we have found a prefix that is
|
114
|
+
# longer than the maximum width of the paragraph. For
|
115
|
+
# example, when maximum width is 5:
|
116
|
+
#
|
117
|
+
# >>>> This is text
|
118
|
+
# >>>> And so is this
|
119
|
+
#
|
120
|
+
# If we cannot do solve the problem, let's return the data
|
121
|
+
# as it was.
|
122
|
+
|
123
|
+
# FIXME: compare agains the new prefix
|
124
|
+
# when @width <= @quote_prefix.length: false
|
125
|
+
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def do_process_without_quotes?
|
130
|
+
|
131
|
+
# decide if this (now unquoted) paragraph needs to be processed
|
132
|
+
|
133
|
+
# * do not process mail signatures
|
134
|
+
# * do not process code
|
135
|
+
|
136
|
+
return case
|
137
|
+
|
138
|
+
# The line marks the beginning of an email signature: do not
|
139
|
+
# process
|
140
|
+
|
141
|
+
# when self[0] == "-- " || self[0] == "-- \n": false
|
142
|
+
when self[0] =~ /\ *-- \n?/: false
|
143
|
+
|
144
|
+
else true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def change_quote()
|
149
|
+
|
150
|
+
return @quote_prefix.strip.squeeze(" ") + " " unless @quote_prefix.empty?
|
151
|
+
return ""
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
def process!(line_breaker, width)
|
156
|
+
|
157
|
+
@width = width
|
158
|
+
|
159
|
+
error = false
|
160
|
+
# pp self
|
161
|
+
|
162
|
+
# this is the time and place to change the quote_prefix to a better one
|
163
|
+
new_quote_prefix = change_quote()
|
164
|
+
|
165
|
+
# some sanity checks
|
166
|
+
# see if we want to process this at all
|
167
|
+
error = true unless do_process?
|
168
|
+
|
169
|
+
# remove the original prefixes from the lines
|
170
|
+
|
171
|
+
self.each do |line|
|
172
|
+
line.slice!(0...@quote_prefix.length)
|
173
|
+
end
|
174
|
+
|
175
|
+
# pp self
|
176
|
+
# see if we want to process the unquoted text
|
177
|
+
error = true unless !error and do_process_without_quotes?
|
178
|
+
|
179
|
+
# error case: just change the prefixes, otherwise do not do
|
180
|
+
# anything
|
181
|
+
if error
|
182
|
+
self.each do |line|
|
183
|
+
line.chomp!
|
184
|
+
line.slice!(0...@whitespace) # take away the extra whitespace after the quote_prefix
|
185
|
+
line.insert(0, new_quote_prefix)
|
186
|
+
end
|
187
|
+
return self
|
188
|
+
end
|
189
|
+
|
190
|
+
# break the lines to a word array
|
191
|
+
|
192
|
+
words = self.inject([]) do |value, line|
|
193
|
+
value += line.chomp.split(' ')
|
194
|
+
end
|
195
|
+
|
196
|
+
# there should be something over the prefix anyway...
|
197
|
+
width = new_quote_prefix.length + 1 unless (width - new_quote_prefix.length) > 0
|
198
|
+
|
199
|
+
# find linebreaks and recreate the prefix: the real thing!
|
200
|
+
self[0..-1] = line_breaker.parse(words, width - new_quote_prefix.length).collect do |line|
|
201
|
+
# pp line
|
202
|
+
line.insert(0, new_quote_prefix)
|
203
|
+
end
|
204
|
+
|
205
|
+
if self.empty? and !@quote_prefix.empty?
|
206
|
+
# If there were no result words, the line might be only a
|
207
|
+
# quoted empty line. By default, we want to save it.
|
208
|
+
# However, if there is no quote prefix, this is a paragraph
|
209
|
+
# break, and they are handled elsewhere. TODO: might be
|
210
|
+
# better to also handle this case here.
|
211
|
+
self[0..-1] = new_quote_prefix
|
212
|
+
end
|
213
|
+
|
214
|
+
return self
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
def split_to_quoted()
|
219
|
+
|
220
|
+
results = Array.new
|
221
|
+
tmp_paragraph = Paragraph.new()
|
222
|
+
previous_quoted = false
|
223
|
+
first = true
|
224
|
+
|
225
|
+
if @whitespace.nil? # not initialized yet!
|
226
|
+
self.find_quote_prefix()
|
227
|
+
end
|
228
|
+
|
229
|
+
# puts "split (quote '" + @quote_prefix + "'):"
|
230
|
+
# pp self
|
231
|
+
|
232
|
+
return self if self.length == 1
|
233
|
+
|
234
|
+
self.each do |line|
|
235
|
+
|
236
|
+
# check if the line is empty after removing the prefix
|
237
|
+
|
238
|
+
# pp "line: '" + line + "', quote: '" + @quote_prefix + "'"
|
239
|
+
|
240
|
+
if (line.strip == @quote_prefix.strip)
|
241
|
+
|
242
|
+
# puts "empty line with only the quote prefix!"
|
243
|
+
|
244
|
+
# end the paragraph
|
245
|
+
results << tmp_paragraph unless tmp_paragraph.empty?
|
246
|
+
|
247
|
+
# add the empty line as a new paragraph
|
248
|
+
empty_paragraph = Paragraph.new()
|
249
|
+
empty_paragraph << line
|
250
|
+
results << empty_paragraph
|
251
|
+
|
252
|
+
# start a new paragraph
|
253
|
+
tmp_paragraph = Paragraph.new()
|
254
|
+
# reset the quoting status
|
255
|
+
first = true
|
256
|
+
|
257
|
+
next # this line is now handled properly, go get the next one
|
258
|
+
end
|
259
|
+
|
260
|
+
if first
|
261
|
+
# note that we need to call the paragraph's own quoted?
|
262
|
+
previous_quoted = self.quoted?(line)
|
263
|
+
# puts "quoting state initialized to " + previous_quoted.to_s
|
264
|
+
# puts "prefix: " + paragraph.quote_prefix
|
265
|
+
first = false
|
266
|
+
end
|
267
|
+
|
268
|
+
if (previous_quoted and self.quoted?(line)) or
|
269
|
+
(!previous_quoted and !self.quoted?(line))
|
270
|
+
|
271
|
+
# add to tmp_paragraph if the quoting status status is the
|
272
|
+
# same
|
273
|
+
tmp_paragraph << line
|
274
|
+
# puts "added: " +line
|
275
|
+
|
276
|
+
else
|
277
|
+
# one quoting block is now at end
|
278
|
+
results << tmp_paragraph
|
279
|
+
# initialize with the old prefix
|
280
|
+
tmp_paragraph = Paragraph.new()
|
281
|
+
tmp_paragraph << line
|
282
|
+
previous_quoted = !previous_quoted
|
283
|
+
# puts "quoting state changed to " + previous_quoted.to_s
|
284
|
+
# puts "added: " +line
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
# also get the last paragraph block
|
290
|
+
results << tmp_paragraph unless tmp_paragraph.empty?
|
291
|
+
# pp results
|
292
|
+
return results
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
def find_prefix(suspicious_level)
|
297
|
+
|
298
|
+
suspicious = 0
|
299
|
+
|
300
|
+
# no use finding prefix if we only have one line
|
301
|
+
return "", "" if self.length <= 1
|
302
|
+
|
303
|
+
# only two lines... let's be careful now
|
304
|
+
suspicious += 1 if self.length == 2
|
305
|
+
|
306
|
+
# find the prefix (incredible find from the web)
|
307
|
+
min, max = self.sort.values_at(0, -1)
|
308
|
+
prefix = (min+max).match(/\A(.*).*(?=.{#{max.length}}\z)\1/m)[1]
|
309
|
+
|
310
|
+
old_prefix = prefix
|
311
|
+
|
312
|
+
# puts "prefix: '" + prefix + "'"
|
313
|
+
|
314
|
+
# is there a prefix?
|
315
|
+
return "", "" if prefix.nil? or prefix.empty?
|
316
|
+
|
317
|
+
# see if the prefix is only whitespace indent
|
318
|
+
return prefix, old_prefix if /\A\s*\Z/.match(prefix)
|
319
|
+
|
320
|
+
# Remove whitespace from right. It's also suspicious if there
|
321
|
+
# isn't any...
|
322
|
+
suspicious += 1 unless prefix.rstrip!
|
323
|
+
|
324
|
+
# see if the prefix library already has a better alternative for
|
325
|
+
# this prefix
|
326
|
+
newprefix = prefix_library(prefix.lstrip)
|
327
|
+
|
328
|
+
return newprefix, old_prefix unless newprefix.nil?
|
329
|
+
|
330
|
+
# our prefix wasn't in the library... this could be a mismatch
|
331
|
+
suspicious += 1
|
332
|
+
|
333
|
+
# only letters in the prefix
|
334
|
+
suspicious += 1 if /[a-zA-Z]/.match(prefix) && prefix.length < 3
|
335
|
+
|
336
|
+
# see if we dare to return the suspected prefix
|
337
|
+
return prefix + " ", old_prefix if suspicious < suspicious_level
|
338
|
+
|
339
|
+
# assume that there is actually no real prefix
|
340
|
+
return "", ""
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rbpar_engine'
|
5
|
+
|
6
|
+
class TestRbParEngine < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@breaker = DynamicBreaker.new()
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_char_length
|
13
|
+
words = "This is a test"
|
14
|
+
# FIXME: index should go from 0 to 3
|
15
|
+
assert_equal(words.length, @breaker.charLength(words.split(" "), 0, 4))
|
16
|
+
# Do it twice to see if the caching doesn't corrupt anything
|
17
|
+
assert_equal(words.length, @breaker.charLength(words.split(" "), 0, 4))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_real_char_length
|
21
|
+
words = "This is a test"
|
22
|
+
# FIXME: index should go from 0 to 3
|
23
|
+
assert_equal(words.length, @breaker.realCharLength(words.split(" "), 0, 4))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_parse
|
27
|
+
words = "Sed eget ligula. Nunc fringilla. In ullamcorper turpis quis tortor. Maecenas fringilla dui aliquet leo. Nulla nec mi ut mauris ultrices sollicitudin. Mauris feugiat ornare massa. Ut vitae dolor sed urna blandit imperdiet. Cras tempus, orci sollicitudin pulvinar ultricies, sapien urna fringilla risus, eu rhoncus metus nisi a risus. Aliquam erat volutpat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis iaculis lorem sit amet neque. Cras quis tellus. Ut molestie eros sit amet nibh blandit luctus. Quisque ac sem. Nulla condimentum eros rhoncus ipsum. Duis enim. Phasellus mattis posuere augue."
|
28
|
+
|
29
|
+
# let's try parsing with several values
|
30
|
+
|
31
|
+
# 1. desired width 45
|
32
|
+
|
33
|
+
resultlines = @breaker.parse(words.split(" "), 45)
|
34
|
+
assert_not_nil(resultlines)
|
35
|
+
# see that no resulting lines are longer than the maximum length
|
36
|
+
resultlines.each do |line|
|
37
|
+
assert(line.length <= 45)
|
38
|
+
end
|
39
|
+
# see that we aren't missing any words or that new words haven't
|
40
|
+
# crept in
|
41
|
+
newwords = resultlines.inject("") do |value, line|
|
42
|
+
if value == ""
|
43
|
+
value = line
|
44
|
+
else
|
45
|
+
value = value + " " + line
|
46
|
+
end
|
47
|
+
end
|
48
|
+
assert_equal(words, newwords)
|
49
|
+
|
50
|
+
# 2. desired width 25
|
51
|
+
|
52
|
+
resultlines = @breaker.parse(words.split(" "), 25)
|
53
|
+
assert_not_nil(resultlines)
|
54
|
+
# see that no resulting lines are longer than the maximum length
|
55
|
+
resultlines.each do |line|
|
56
|
+
assert(line.length <= 25, "line length was " + line.length.to_s)
|
57
|
+
end
|
58
|
+
# see that we aren't missing any words or that new words haven't
|
59
|
+
# crept in
|
60
|
+
newwords = resultlines.inject("") do |value, line|
|
61
|
+
if value == ""
|
62
|
+
value = line
|
63
|
+
else
|
64
|
+
value = value + " " + line
|
65
|
+
end
|
66
|
+
end
|
67
|
+
assert_equal(words, newwords)
|
68
|
+
|
69
|
+
# 3. desired width 5. Now there are words that are longer than
|
70
|
+
# 5, and that's okay. Still, there must not be lines consisting
|
71
|
+
# of several words that are over 5 characters long.
|
72
|
+
|
73
|
+
resultlines = @breaker.parse(words.split(" "), 5)
|
74
|
+
assert_not_nil(resultlines)
|
75
|
+
# see that no resulting lines are longer than the maximum length
|
76
|
+
resultlines.each do |line|
|
77
|
+
# puts line.length
|
78
|
+
if (line.length > 5)
|
79
|
+
assert_no_match(/ /, line)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# see that we aren't missing any words or that new words haven't
|
83
|
+
# crept in
|
84
|
+
newwords = resultlines.inject("") do |value, line|
|
85
|
+
if value == ""
|
86
|
+
value = line
|
87
|
+
else
|
88
|
+
value = value + " " + line
|
89
|
+
end
|
90
|
+
end
|
91
|
+
assert_equal(words, newwords)
|
92
|
+
|
93
|
+
# 4. Test from Wikipedia
|
94
|
+
# (http://en.wikipedia.org/wiki/Word_wrap)
|
95
|
+
|
96
|
+
words2 = "aaa bb cc ddddd"
|
97
|
+
|
98
|
+
# line width is 6
|
99
|
+
#
|
100
|
+
# greedy algorithm:
|
101
|
+
#
|
102
|
+
# aaa bb
|
103
|
+
# cc
|
104
|
+
# ddddd
|
105
|
+
#
|
106
|
+
# optimal algorithm:
|
107
|
+
#
|
108
|
+
# aaa
|
109
|
+
# bb cc
|
110
|
+
# ddddd
|
111
|
+
|
112
|
+
resultlines = @breaker.parse(words2.split(" "), 6)
|
113
|
+
|
114
|
+
# resultlines.each do |line|
|
115
|
+
# puts line
|
116
|
+
# end
|
117
|
+
|
118
|
+
assert_equal("aaa", resultlines[0])
|
119
|
+
assert_equal("bb cc", resultlines[1])
|
120
|
+
assert_equal("ddddd", resultlines[2])
|
121
|
+
|
122
|
+
# 5. Test only one line
|
123
|
+
|
124
|
+
words3 = "laama fdsf fds f eee ddd lll eee linna lumi lunni"
|
125
|
+
|
126
|
+
resultlines = @breaker.parse(words3.split(" "), 63)
|
127
|
+
|
128
|
+
assert_equal("laama fdsf fds f eee ddd lll eee linna lumi lunni", resultlines[0])
|
129
|
+
|
130
|
+
# 6. Test only one word
|
131
|
+
|
132
|
+
resultlines = @breaker.parse(["test"], 63)
|
133
|
+
|
134
|
+
assert_equal("test", resultlines[0])
|
135
|
+
|
136
|
+
# 6. Test only one word (longer than allowed)
|
137
|
+
|
138
|
+
resultlines = @breaker.parse(["testingtesting"], 10)
|
139
|
+
|
140
|
+
assert_equal("testingtesting", resultlines[0])
|
141
|
+
|
142
|
+
# 7. Test only two words
|
143
|
+
|
144
|
+
resultlines = @breaker.parse(["testing1", "testing2"], 10)
|
145
|
+
|
146
|
+
assert_equal("testing1", resultlines[0])
|
147
|
+
assert_equal("testing2", resultlines[1])
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,212 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rbpar_main'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
class TestRbParMain < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_lines
|
10
|
+
|
11
|
+
rbpar1 = RbParIterator.new(63)
|
12
|
+
|
13
|
+
lines1 = ["\n"]
|
14
|
+
rbpar1 << lines1
|
15
|
+
lines1 = rbpar1.collect
|
16
|
+
assert_equal("", lines1[0][0])
|
17
|
+
assert_nil(lines1[0][1])
|
18
|
+
assert_nil(lines1[1])
|
19
|
+
|
20
|
+
rbpar2 = RbParIterator.new(63)
|
21
|
+
|
22
|
+
lines2 = ["\n\n"]
|
23
|
+
rbpar2 << lines2
|
24
|
+
lines2 = rbpar2.collect
|
25
|
+
assert_equal("", lines2[0][0])
|
26
|
+
assert_equal("", lines2[0][1])
|
27
|
+
assert_nil(lines2[1])
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_paragraphs
|
32
|
+
|
33
|
+
# very basic one line test
|
34
|
+
|
35
|
+
rbpar1 = RbParIterator.new(63)
|
36
|
+
|
37
|
+
lines1 = ["lunni\n", "lumi\n", "lumikki\n", "luoto\n"]
|
38
|
+
|
39
|
+
rbpar1 << lines1
|
40
|
+
|
41
|
+
lines1 = rbpar1.collect
|
42
|
+
assert_equal("lunni lumi lumikki luoto", lines1[0][0])
|
43
|
+
|
44
|
+
# very basic one line test
|
45
|
+
|
46
|
+
rbpar2 = RbParIterator.new(10)
|
47
|
+
|
48
|
+
lines2 = ["This is a test of splitting the lines to two lines\n"]
|
49
|
+
|
50
|
+
rbpar2 << lines2
|
51
|
+
|
52
|
+
lines2 = rbpar2.collect
|
53
|
+
|
54
|
+
# check the line lengths
|
55
|
+
lines2.each do |paragraph|
|
56
|
+
paragraph.each do |line|
|
57
|
+
assert(line.length <= 10, "line length was " + line.length.to_s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# for regression testing: the results should be like this
|
62
|
+
assert_equal("This is", lines2[0][0])
|
63
|
+
assert_equal("a test of", lines2[0][1])
|
64
|
+
assert_equal("splitting", lines2[0][2])
|
65
|
+
assert_equal("the lines", lines2[0][3])
|
66
|
+
assert_equal("to two", lines2[0][4])
|
67
|
+
assert_equal("lines", lines2[0][5])
|
68
|
+
|
69
|
+
# test with an actual email
|
70
|
+
|
71
|
+
rbpar3 = RbParIterator.new(50)
|
72
|
+
|
73
|
+
lines3 = [
|
74
|
+
"On 12/1/07, Lorem Ipsum wrote:\n",
|
75
|
+
"\n",
|
76
|
+
"> Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n",
|
77
|
+
"> Praesent viverra magna sed urna.\n",
|
78
|
+
"> \n",
|
79
|
+
"> On 11/29/07, The previous Lorem Ipsum wrote:\n",
|
80
|
+
"> > Vivamus imperdiet purus eget velit. Pellentesque vehicula\n",
|
81
|
+
"> > gravida justo. In facilisis. Curabitur at tortor eu ante\n",
|
82
|
+
"> > mattis pulvinar. Cras lobortis, augue malesuada accumsan\n",
|
83
|
+
"> > vehicula, erat tortor ultricies nulla, ac interdum odio tortor.\n",
|
84
|
+
"\n",
|
85
|
+
"Phasellus faucibus porta nunc.\n",
|
86
|
+
"Vestibulum vel lectus.\n",
|
87
|
+
"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos."
|
88
|
+
]
|
89
|
+
|
90
|
+
rbpar3 << lines3
|
91
|
+
|
92
|
+
lines3 = rbpar3.collect
|
93
|
+
|
94
|
+
assert_equal("On 12/1/07, Lorem Ipsum wrote:", lines3[0][0])
|
95
|
+
|
96
|
+
# Paragraph break is part of the lines list: this is so that the
|
97
|
+
# empty lines would not be counted twice as paragraph breaks
|
98
|
+
# anymore, but we still would get two '\n' characters after a
|
99
|
+
# line break in the data.
|
100
|
+
assert_equal("", lines3[0][1])
|
101
|
+
|
102
|
+
assert_equal("> Lorem ipsum dolor sit amet, consectetuer", lines3[1][0])
|
103
|
+
assert_equal("> adipiscing elit. Praesent viverra magna sed", lines3[1][1])
|
104
|
+
assert_equal("> urna.", lines3[1][2])
|
105
|
+
assert_equal("> ", lines3[1][3])
|
106
|
+
|
107
|
+
# Note that these are now part of the same paragraph as the
|
108
|
+
# previous lines. This is because we don't want an empty line
|
109
|
+
# between the two paragraphs.
|
110
|
+
assert_equal("> On 11/29/07, The previous Lorem Ipsum wrote:", lines3[1][4])
|
111
|
+
assert_equal("> > Vivamus imperdiet purus eget velit.", lines3[1][5])
|
112
|
+
assert_equal("> > Pellentesque vehicula gravida justo. In", lines3[1][6])
|
113
|
+
assert_equal("> > facilisis. Curabitur at tortor eu ante mattis", lines3[1][7])
|
114
|
+
assert_equal("> > pulvinar. Cras lobortis, augue malesuada", lines3[1][8])
|
115
|
+
assert_equal("> > accumsan vehicula, erat tortor ultricies", lines3[1][9])
|
116
|
+
assert_equal("> > nulla, ac interdum odio tortor.", lines3[1][10])
|
117
|
+
assert_equal("", lines3[1][11])
|
118
|
+
|
119
|
+
assert_equal("Phasellus faucibus porta nunc. Vestibulum", lines3[2][0])
|
120
|
+
assert_equal("vel lectus. Class aptent taciti sociosqu ad", lines3[2][1])
|
121
|
+
assert_equal("litora torquent per conubia nostra, per inceptos", lines3[2][2])
|
122
|
+
assert_equal("hymenaeos.", lines3[2][3])
|
123
|
+
|
124
|
+
rbpar4 = RbParIterator.new(6)
|
125
|
+
|
126
|
+
lines4 = [ "aaa bb cc ddddd" ]
|
127
|
+
|
128
|
+
rbpar4 << lines4
|
129
|
+
|
130
|
+
lines4 = rbpar4.collect
|
131
|
+
|
132
|
+
assert_equal("aaa", lines4[0][0])
|
133
|
+
assert_equal("bb cc", lines4[0][1])
|
134
|
+
assert_equal("ddddd", lines4[0][2])
|
135
|
+
|
136
|
+
# Check the handling of empty quoted lines.
|
137
|
+
# if this happens:
|
138
|
+
#
|
139
|
+
# > text text
|
140
|
+
# >
|
141
|
+
# > text
|
142
|
+
#
|
143
|
+
# the paragraph break should be respected no matter how much or
|
144
|
+
# how little whitespace is on the middle line.
|
145
|
+
|
146
|
+
rbpar5 = RbParIterator.new(15)
|
147
|
+
lines5 = [ "> text text\n", ">\n", "> text\n" ]
|
148
|
+
rbpar5 << lines5
|
149
|
+
|
150
|
+
lines5 = rbpar5.collect
|
151
|
+
|
152
|
+
assert_equal("> text text", lines5[0][0])
|
153
|
+
assert_equal("> ", lines5[0][1])
|
154
|
+
assert_equal("> text", lines5[0][2])
|
155
|
+
|
156
|
+
rbpar6 = RbParIterator.new(15)
|
157
|
+
lines6 = [ "> text text\n", "> \n", "> text\n" ]
|
158
|
+
rbpar6 << lines6
|
159
|
+
|
160
|
+
lines6 = rbpar6.collect
|
161
|
+
|
162
|
+
assert_equal("> text text", lines6[0][0])
|
163
|
+
assert_equal("> ", lines6[0][1])
|
164
|
+
assert_equal("> text", lines6[0][2])
|
165
|
+
|
166
|
+
rbpar7 = RbParIterator.new(15)
|
167
|
+
lines7 = [ "> text text\n", "\n", "> text\n" ]
|
168
|
+
rbpar7 << lines7
|
169
|
+
|
170
|
+
lines7 = rbpar7.collect
|
171
|
+
|
172
|
+
assert_equal("> text text", lines7[0][0])
|
173
|
+
assert_equal("", lines7[0][1])
|
174
|
+
assert_equal("> text", lines7[1][0])
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_signature
|
179
|
+
|
180
|
+
# test that signature paragraphs behave correctly
|
181
|
+
|
182
|
+
# TODO: refactor to rbpar_paragraph_test?
|
183
|
+
|
184
|
+
lines_sig_1 = ["-- \n", " - NanoNano\n"]
|
185
|
+
|
186
|
+
rbpar_sig_1 = RbParIterator.new(68)
|
187
|
+
rbpar_sig_1 << lines_sig_1
|
188
|
+
lines_sig_1 = rbpar_sig_1.collect
|
189
|
+
assert_equal("-- ", lines_sig_1[0][0])
|
190
|
+
assert_equal(" - NanoNano", lines_sig_1[0][1])
|
191
|
+
# pp lines_sig_1
|
192
|
+
|
193
|
+
lines_sig_2 = [">-- \n", "> - NanoNano\n"]
|
194
|
+
|
195
|
+
rbpar_sig_2 = RbParIterator.new(68)
|
196
|
+
rbpar_sig_2 << lines_sig_2
|
197
|
+
lines_sig_2 = rbpar_sig_2.collect
|
198
|
+
assert_equal("> -- ", lines_sig_2[0][0])
|
199
|
+
assert_equal("> - NanoNano", lines_sig_2[0][1])
|
200
|
+
# pp lines_sig_2
|
201
|
+
|
202
|
+
lines_sig_3 = ["> -- \n", "> - NanoNano\n"]
|
203
|
+
|
204
|
+
rbpar_sig_3 = RbParIterator.new(68)
|
205
|
+
rbpar_sig_3 << lines_sig_3
|
206
|
+
lines_sig_3 = rbpar_sig_3.collect
|
207
|
+
assert_equal("> -- ", lines_sig_3[0][0])
|
208
|
+
assert_equal("> - NanoNano", lines_sig_3[0][1])
|
209
|
+
# pp lines_sig_3
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|