removing log dir from .gitignore
[monkeycharger.git] / vendor / rails / actionmailer / lib / action_mailer / vendor / text / format.rb
blobde054db83e48ef6df41906e10ddbabf79977c56d
1 #--\r
2 # Text::Format for Ruby\r
3 # Version 0.63\r
4 #\r
5 # Copyright (c) 2002 - 2003 Austin Ziegler\r
6 #\r
7 # $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $\r
8 #\r
9 # ==========================================================================\r
10 # Revision History ::\r
11 # YYYY.MM.DD  Change ID   Developer\r
12 #             Description\r
13 # --------------------------------------------------------------------------\r
14 # 2002.10.18              Austin Ziegler\r
15 #             Fixed a minor problem with tabs not being counted. Changed\r
16 #             abbreviations from Hash to Array to better suit Ruby's\r
17 #             capabilities. Fixed problems with the way that Array arguments\r
18 #             are handled in calls to the major object types, excepting in\r
19 #             Text::Format#expand and Text::Format#unexpand (these will\r
20 #             probably need to be fixed).\r
21 # 2002.10.30              Austin Ziegler\r
22 #             Fixed the ordering of the <=> for binary tests. Fixed\r
23 #             Text::Format#expand and Text::Format#unexpand to handle array\r
24 #             arguments better.\r
25 # 2003.01.24              Austin Ziegler\r
26 #             Fixed a problem with Text::Format::RIGHT_FILL handling where a\r
27 #             single word is larger than #columns. Removed Comparable\r
28 #             capabilities (<=> doesn't make sense; == does). Added Symbol\r
29 #             equivalents for the Hash initialization. Hash initialization has\r
30 #             been modified so that values are set as follows (Symbols are\r
31 #             highest priority; strings are middle; defaults are lowest):\r
32 #                 @columns = arg[:columns] || arg['columns'] || @columns\r
33 #             Added #hard_margins, #split_rules, #hyphenator, and #split_words.\r
34 # 2003.02.07              Austin Ziegler\r
35 #             Fixed the installer for proper case-sensitive handling.\r
36 # 2003.03.28              Austin Ziegler\r
37 #             Added the ability for a hyphenator to receive the formatter\r
38 #             object. Fixed a bug for strings matching /\A\s*\Z/ failing\r
39 #             entirely. Fixed a test case failing under 1.6.8. \r
40 # 2003.04.04              Austin Ziegler\r
41 #             Handle the case of hyphenators returning nil for first/rest.\r
42 # 2003.09.17          Austin Ziegler\r
43 #             Fixed a problem where #paragraphs(" ") was raising\r
44 #             NoMethodError.\r
45 #\r
46 # ==========================================================================\r
47 #++\r
49 module Text #:nodoc:\r
50    # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It\r
51    # is available under Ruby's licence, the Perl Artistic licence, or the\r
52    # GNU GPL version 2 (or at your option, any later version). As a\r
53    # special exception, for use with official Rails (provided by the\r
54    # rubyonrails.org development team) and any project created with\r
55    # official Rails, the following alternative MIT-style licence may be\r
56    # used:\r
57    #\r
58    # == Text::Format Licence for Rails and Rails Applications\r
59    # Permission is hereby granted, free of charge, to any person\r
60    # obtaining a copy of this software and associated documentation files\r
61    # (the "Software"), to deal in the Software without restriction,\r
62    # including without limitation the rights to use, copy, modify, merge,\r
63    # publish, distribute, sublicense, and/or sell copies of the Software,\r
64    # and to permit persons to whom the Software is furnished to do so,\r
65    # subject to the following conditions:\r
66    #\r
67    # * The names of its contributors may not be used to endorse or\r
68    #   promote products derived from this software without specific prior\r
69    #   written permission.\r
70    #\r
71    # The above copyright notice and this permission notice shall be\r
72    # included in all copies or substantial portions of the Software.\r
73    #\r
74    # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
75    # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
76    # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
77    # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
78    # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
79    # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
80    # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
81    # SOFTWARE.  \r
82    class Format\r
83     VERSION = '0.63'\r
85       # Local abbreviations. More can be added with Text::Format.abbreviations\r
86     ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ]\r
88       # Formatting values\r
89     LEFT_ALIGN  = 0\r
90     RIGHT_ALIGN = 1\r
91     RIGHT_FILL  = 2\r
92     JUSTIFY     = 3\r
94       # Word split modes (only applies when #hard_margins is true).\r
95     SPLIT_FIXED                     = 1\r
96     SPLIT_CONTINUATION              = 2\r
97     SPLIT_HYPHENATION               = 4\r
98     SPLIT_CONTINUATION_FIXED        = SPLIT_CONTINUATION | SPLIT_FIXED\r
99     SPLIT_HYPHENATION_FIXED         = SPLIT_HYPHENATION | SPLIT_FIXED\r
100     SPLIT_HYPHENATION_CONTINUATION  = SPLIT_HYPHENATION | SPLIT_CONTINUATION\r
101     SPLIT_ALL                       = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED\r
103       # Words forcibly split by Text::Format will be stored as split words.\r
104       # This class represents a word forcibly split.\r
105     class SplitWord\r
106         # The word that was split.\r
107       attr_reader :word\r
108         # The first part of the word that was split.\r
109       attr_reader :first\r
110         # The remainder of the word that was split.\r
111       attr_reader :rest\r
113       def initialize(word, first, rest) #:nodoc:\r
114         @word = word\r
115         @first = first\r
116         @rest = rest\r
117       end\r
118     end\r
120   private\r
121     LEQ_RE = /[.?!]['"]?$/\r
123     def brk_re(i) #:nodoc:\r
124       %r/((?:\S+\s+){#{i}})(.+)/\r
125     end\r
127     def posint(p) #:nodoc:\r
128       p.to_i.abs\r
129     end\r
131   public\r
132       # Compares two Text::Format objects. All settings of the objects are\r
133       # compared *except* #hyphenator. Generated results (e.g., #split_words)\r
134       # are not compared, either.\r
135     def ==(o)\r
136       (@text          ==  o.text)           &&\r
137       (@columns       ==  o.columns)        &&\r
138       (@left_margin   ==  o.left_margin)    &&\r
139       (@right_margin  ==  o.right_margin)   &&\r
140       (@hard_margins  ==  o.hard_margins)   &&\r
141       (@split_rules   ==  o.split_rules)    &&\r
142       (@first_indent  ==  o.first_indent)   &&\r
143       (@body_indent   ==  o.body_indent)    &&\r
144       (@tag_text      ==  o.tag_text)       &&\r
145       (@tabstop       ==  o.tabstop)        &&\r
146       (@format_style  ==  o.format_style)   &&\r
147       (@extra_space   ==  o.extra_space)    &&\r
148       (@tag_paragraph ==  o.tag_paragraph)  &&\r
149       (@nobreak       ==  o.nobreak)        &&\r
150       (@abbreviations ==  o.abbreviations)  &&\r
151       (@nobreak_regex ==  o.nobreak_regex)\r
152     end\r
154       # The text to be manipulated. Note that value is optional, but if the\r
155       # formatting functions are called without values, this text is what will\r
156       # be formatted.\r
157       #\r
158       # *Default*::       <tt>[]</tt>\r
159       # <b>Used in</b>::  All methods\r
160     attr_accessor :text\r
162       # The total width of the format area. The margins, indentation, and text\r
163       # are formatted into this space.\r
164       #\r
165       #                             COLUMNS\r
166       #  <-------------------------------------------------------------->\r
167       #  <-----------><------><---------------------------><------------>\r
168       #   left margin  indent  text is formatted into here  right margin\r
169       #\r
170       # *Default*::       <tt>72</tt>\r
171       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
172       #                   <tt>#center</tt>\r
173     attr_reader :columns\r
175       # The total width of the format area. The margins, indentation, and text\r
176       # are formatted into this space. The value provided is silently\r
177       # converted to a positive integer.\r
178       #\r
179       #                             COLUMNS\r
180       #  <-------------------------------------------------------------->\r
181       #  <-----------><------><---------------------------><------------>\r
182       #   left margin  indent  text is formatted into here  right margin\r
183       #\r
184       # *Default*::       <tt>72</tt>\r
185       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
186       #                   <tt>#center</tt>\r
187     def columns=(c)\r
188       @columns = posint(c)\r
189     end\r
191       # The number of spaces used for the left margin.\r
192       #\r
193       #                             columns\r
194       #  <-------------------------------------------------------------->\r
195       #  <-----------><------><---------------------------><------------>\r
196       #   LEFT MARGIN  indent  text is formatted into here  right margin\r
197       #\r
198       # *Default*::       <tt>0</tt>\r
199       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
200       #                   <tt>#center</tt>\r
201     attr_reader :left_margin\r
203       # The number of spaces used for the left margin. The value provided is\r
204       # silently converted to a positive integer value.\r
205       #\r
206       #                             columns\r
207       #  <-------------------------------------------------------------->\r
208       #  <-----------><------><---------------------------><------------>\r
209       #   LEFT MARGIN  indent  text is formatted into here  right margin\r
210       #\r
211       # *Default*::       <tt>0</tt>\r
212       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
213       #                   <tt>#center</tt>\r
214     def left_margin=(left)\r
215       @left_margin = posint(left)\r
216     end\r
218       # The number of spaces used for the right margin.\r
219       #\r
220       #                             columns\r
221       #  <-------------------------------------------------------------->\r
222       #  <-----------><------><---------------------------><------------>\r
223       #   left margin  indent  text is formatted into here  RIGHT MARGIN\r
224       #\r
225       # *Default*::       <tt>0</tt>\r
226       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
227       #                   <tt>#center</tt>\r
228     attr_reader :right_margin\r
230       # The number of spaces used for the right margin. The value provided is\r
231       # silently converted to a positive integer value.\r
232       #\r
233       #                             columns\r
234       #  <-------------------------------------------------------------->\r
235       #  <-----------><------><---------------------------><------------>\r
236       #   left margin  indent  text is formatted into here  RIGHT MARGIN\r
237       #\r
238       # *Default*::       <tt>0</tt>\r
239       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>,\r
240       #                   <tt>#center</tt>\r
241     def right_margin=(r)\r
242       @right_margin = posint(r)\r
243     end\r
245       # The number of spaces to indent the first line of a paragraph.\r
246       #\r
247       #                             columns\r
248       #  <-------------------------------------------------------------->\r
249       #  <-----------><------><---------------------------><------------>\r
250       #   left margin  INDENT  text is formatted into here  right margin\r
251       #\r
252       # *Default*::       <tt>4</tt>\r
253       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
254     attr_reader :first_indent\r
256       # The number of spaces to indent the first line of a paragraph. The\r
257       # value provided is silently converted to a positive integer value.\r
258       #\r
259       #                             columns\r
260       #  <-------------------------------------------------------------->\r
261       #  <-----------><------><---------------------------><------------>\r
262       #   left margin  INDENT  text is formatted into here  right margin\r
263       #\r
264       # *Default*::       <tt>4</tt>\r
265       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
266     def first_indent=(f)\r
267       @first_indent = posint(f)\r
268     end\r
270       # The number of spaces to indent all lines after the first line of a\r
271       # paragraph.\r
272       #\r
273       #                             columns\r
274       #  <-------------------------------------------------------------->\r
275       #  <-----------><------><---------------------------><------------>\r
276       #   left margin  INDENT  text is formatted into here  right margin\r
277       #\r
278       # *Default*::       <tt>0</tt>\r
279       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
280   attr_reader :body_indent\r
282       # The number of spaces to indent all lines after the first line of\r
283       # a paragraph. The value provided is silently converted to a\r
284       # positive integer value.\r
285       #\r
286       #                             columns\r
287       #  <-------------------------------------------------------------->\r
288       #  <-----------><------><---------------------------><------------>\r
289       #   left margin  INDENT  text is formatted into here  right margin\r
290       #\r
291       # *Default*::       <tt>0</tt>\r
292       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
293     def body_indent=(b)\r
294       @body_indent = posint(b)\r
295     end\r
297       # Normally, words larger than the format area will be placed on a line\r
298       # by themselves. Setting this to +true+ will force words larger than the\r
299       # format area to be split into one or more "words" each at most the size\r
300       # of the format area. The first line and the original word will be\r
301       # placed into <tt>#split_words</tt>. Note that this will cause the\r
302       # output to look *similar* to a #format_style of JUSTIFY. (Lines will be\r
303       # filled as much as possible.)\r
304       #\r
305       # *Default*::       +false+\r
306       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
307     attr_accessor :hard_margins\r
309       # An array of words split during formatting if #hard_margins is set to\r
310       # +true+.\r
311       #   #split_words << Text::Format::SplitWord.new(word, first, rest)\r
312     attr_reader :split_words\r
314       # The object responsible for hyphenating. It must respond to\r
315       # #hyphenate_to(word, size) or #hyphenate_to(word, size, formatter) and\r
316       # return an array of the word split into two parts; if there is a\r
317       # hyphenation mark to be applied, responsibility belongs to the\r
318       # hyphenator object. The size is the MAXIMUM size permitted, including\r
319       # any hyphenation marks. If the #hyphenate_to method has an arity of 3,\r
320       # the formatter will be provided to the method. This allows the\r
321       # hyphenator to make decisions about the hyphenation based on the\r
322       # formatting rules.\r
323       #\r
324       # *Default*::       +nil+\r
325       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
326     attr_reader :hyphenator\r
328       # The object responsible for hyphenating. It must respond to\r
329       # #hyphenate_to(word, size) and return an array of the word hyphenated\r
330       # into two parts. The size is the MAXIMUM size permitted, including any\r
331       # hyphenation marks.\r
332       #\r
333       # *Default*::       +nil+\r
334       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
335     def hyphenator=(h)\r
336       raise ArgumentError, "#{h.inspect} is not a valid hyphenator." unless h.respond_to?(:hyphenate_to)\r
337       arity = h.method(:hyphenate_to).arity\r
338       raise ArgumentError, "#{h.inspect} must have exactly two or three arguments." unless [2, 3].include?(arity)\r
339       @hyphenator = h\r
340       @hyphenator_arity = arity\r
341     end\r
343       # Specifies the split mode; used only when #hard_margins is set to\r
344       # +true+. Allowable values are:\r
345       # [+SPLIT_FIXED+]         The word will be split at the number of\r
346       #                         characters needed, with no marking at all.\r
347       #      repre\r
348       #      senta\r
349       #      ion\r
350       # [+SPLIT_CONTINUATION+]  The word will be split at the number of\r
351       #                         characters needed, with a C-style continuation\r
352       #                         character. If a word is the only item on a\r
353       #                         line and it cannot be split into an\r
354       #                         appropriate size, SPLIT_FIXED will be used.\r
355       #       repr\\r
356       #       esen\\r
357       #       tati\\r
358       #       on\r
359       # [+SPLIT_HYPHENATION+]   The word will be split according to the\r
360       #                         hyphenator specified in #hyphenator. If there\r
361       #                         is no #hyphenator specified, works like\r
362       #                         SPLIT_CONTINUATION. The example is using\r
363       #                         TeX::Hyphen. If a word is the only item on a\r
364       #                         line and it cannot be split into an\r
365       #                         appropriate size, SPLIT_CONTINUATION mode will\r
366       #                         be used.\r
367       #       rep-\r
368       #       re-\r
369       #       sen-\r
370       #       ta-\r
371       #       tion\r
372       #\r
373       # *Default*::       <tt>Text::Format::SPLIT_FIXED</tt>\r
374       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
375     attr_reader :split_rules\r
377       # Specifies the split mode; used only when #hard_margins is set to\r
378       # +true+. Allowable values are:\r
379       # [+SPLIT_FIXED+]         The word will be split at the number of\r
380       #                         characters needed, with no marking at all.\r
381       #      repre\r
382       #      senta\r
383       #      ion\r
384       # [+SPLIT_CONTINUATION+]  The word will be split at the number of\r
385       #                         characters needed, with a C-style continuation\r
386       #                         character.\r
387       #       repr\\r
388       #       esen\\r
389       #       tati\\r
390       #       on\r
391       # [+SPLIT_HYPHENATION+]   The word will be split according to the\r
392       #                         hyphenator specified in #hyphenator. If there\r
393       #                         is no #hyphenator specified, works like\r
394       #                         SPLIT_CONTINUATION. The example is using\r
395       #                         TeX::Hyphen as the #hyphenator.\r
396       #       rep-\r
397       #       re-\r
398       #       sen-\r
399       #       ta-\r
400       #       tion\r
401       #\r
402       # These values can be bitwise ORed together (e.g., <tt>SPLIT_FIXED |\r
403       # SPLIT_CONTINUATION</tt>) to provide fallback split methods. In the\r
404       # example given, an attempt will be made to split the word using the\r
405       # rules of SPLIT_CONTINUATION; if there is not enough room, the word\r
406       # will be split with the rules of SPLIT_FIXED. These combinations are\r
407       # also available as the following values:\r
408       # * +SPLIT_CONTINUATION_FIXED+\r
409       # * +SPLIT_HYPHENATION_FIXED+\r
410       # * +SPLIT_HYPHENATION_CONTINUATION+\r
411       # * +SPLIT_ALL+\r
412       #\r
413       # *Default*::       <tt>Text::Format::SPLIT_FIXED</tt>\r
414       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
415     def split_rules=(s)\r
416       raise ArgumentError, "Invalid value provided for split_rules." if ((s < SPLIT_FIXED) || (s > SPLIT_ALL))\r
417       @split_rules = s\r
418     end\r
420       # Indicates whether sentence terminators should be followed by a single\r
421       # space (+false+), or two spaces (+true+).\r
422       #\r
423       # *Default*::       +false+\r
424       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
425     attr_accessor :extra_space\r
427       # Defines the current abbreviations as an array. This is only used if\r
428       # extra_space is turned on.\r
429       #\r
430       # If one is abbreviating "President" as "Pres." (abbreviations =\r
431       # ["Pres"]), then the results of formatting will be as illustrated in\r
432       # the table below:\r
433       #\r
434       #       extra_space  |  include?        |  !include?\r
435       #         true       |  Pres. Lincoln   |  Pres.  Lincoln\r
436       #         false      |  Pres. Lincoln   |  Pres. Lincoln\r
437       #\r
438       # *Default*::       <tt>{}</tt>\r
439       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
440     attr_accessor :abbreviations\r
442       # Indicates whether the formatting of paragraphs should be done with\r
443       # tagged paragraphs. Useful only with <tt>#tag_text</tt>.\r
444       #\r
445       # *Default*::       +false+\r
446       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
447     attr_accessor :tag_paragraph\r
449       # The array of text to be placed before each paragraph when\r
450       # <tt>#tag_paragraph</tt> is +true+. When <tt>#format()</tt> is called,\r
451       # only the first element of the array is used. When <tt>#paragraphs</tt>\r
452       # is called, then each entry in the array will be used once, with\r
453       # corresponding paragraphs. If the tag elements are exhausted before the\r
454       # text is exhausted, then the remaining paragraphs will not be tagged.\r
455       # Regardless of indentation settings, a blank line will be inserted\r
456       # between all paragraphs when <tt>#tag_paragraph</tt> is +true+.\r
457       #\r
458       # *Default*::       <tt>[]</tt>\r
459       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
460     attr_accessor :tag_text\r
462       # Indicates whether or not the non-breaking space feature should be\r
463       # used.\r
464       #\r
465       # *Default*::       +false+\r
466       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
467     attr_accessor :nobreak\r
469       # A hash which holds the regular expressions on which spaces should not\r
470       # be broken. The hash is set up such that the key is the first word and\r
471       # the value is the second word.\r
472       #\r
473       # For example, if +nobreak_regex+ contains the following hash:\r
474       #\r
475       #   { '^Mrs?\.$' => '\S+$', '^\S+$' => '^(?:S|J)r\.$'}\r
476       #\r
477       # Then "Mr. Jones", "Mrs. Jones", and "Jones Jr." would not be broken.\r
478       # If this simple matching algorithm indicates that there should not be a\r
479       # break at the current end of line, then a backtrack is done until there\r
480       # are two words on which line breaking is permitted. If two such words\r
481       # are not found, then the end of the line will be broken *regardless*.\r
482       # If there is a single word on the current line, then no backtrack is\r
483       # done and the word is stuck on the end.\r
484       #\r
485       # *Default*::       <tt>{}</tt>\r
486       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
487     attr_accessor :nobreak_regex\r
489       # Indicates the number of spaces that a single tab represents.\r
490       #\r
491       # *Default*::       <tt>8</tt>\r
492       # <b>Used in</b>::  <tt>#expand</tt>, <tt>#unexpand</tt>,\r
493       #                   <tt>#paragraphs</tt>\r
494     attr_reader :tabstop\r
496       # Indicates the number of spaces that a single tab represents.\r
497       #\r
498       # *Default*::       <tt>8</tt>\r
499       # <b>Used in</b>::  <tt>#expand</tt>, <tt>#unexpand</tt>,\r
500       #                   <tt>#paragraphs</tt>\r
501     def tabstop=(t)\r
502       @tabstop = posint(t)\r
503     end\r
505       # Specifies the format style. Allowable values are:\r
506       # [+LEFT_ALIGN+]    Left justified, ragged right.\r
507       #      |A paragraph that is|\r
508       #      |left aligned.|\r
509       # [+RIGHT_ALIGN+]   Right justified, ragged left.\r
510       #      |A paragraph that is|\r
511       #      |     right aligned.|\r
512       # [+RIGHT_FILL+]    Left justified, right ragged, filled to width by\r
513       #                   spaces. (Essentially the same as +LEFT_ALIGN+ except\r
514       #                   that lines are padded on the right.)\r
515       #      |A paragraph that is|\r
516       #      |left aligned.      |\r
517       # [+JUSTIFY+]       Fully justified, words filled to width by spaces,\r
518       #                   except the last line.\r
519       #      |A paragraph  that|\r
520       #      |is     justified.|\r
521       #\r
522       # *Default*::       <tt>Text::Format::LEFT_ALIGN</tt>\r
523       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
524     attr_reader :format_style\r
526       # Specifies the format style. Allowable values are:\r
527       # [+LEFT_ALIGN+]    Left justified, ragged right.\r
528       #      |A paragraph that is|\r
529       #      |left aligned.|\r
530       # [+RIGHT_ALIGN+]   Right justified, ragged left.\r
531       #      |A paragraph that is|\r
532       #      |     right aligned.|\r
533       # [+RIGHT_FILL+]    Left justified, right ragged, filled to width by\r
534       #                   spaces. (Essentially the same as +LEFT_ALIGN+ except\r
535       #                   that lines are padded on the right.)\r
536       #      |A paragraph that is|\r
537       #      |left aligned.      |\r
538       # [+JUSTIFY+]       Fully justified, words filled to width by spaces.\r
539       #      |A paragraph  that|\r
540       #      |is     justified.|\r
541       #\r
542       # *Default*::       <tt>Text::Format::LEFT_ALIGN</tt>\r
543       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
544     def format_style=(fs)\r
545       raise ArgumentError, "Invalid value provided for format_style." if ((fs < LEFT_ALIGN) || (fs > JUSTIFY))\r
546       @format_style = fs\r
547     end\r
549       # Indicates that the format style is left alignment.\r
550       #\r
551       # *Default*::       +true+\r
552       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
553     def left_align?\r
554       return @format_style == LEFT_ALIGN\r
555     end\r
557       # Indicates that the format style is right alignment.\r
558       #\r
559       # *Default*::       +false+\r
560       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
561     def right_align?\r
562       return @format_style == RIGHT_ALIGN\r
563     end\r
565       # Indicates that the format style is right fill.\r
566       #\r
567       # *Default*::       +false+\r
568       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
569     def right_fill?\r
570       return @format_style == RIGHT_FILL\r
571     end\r
573       # Indicates that the format style is full justification.\r
574       #\r
575       # *Default*::       +false+\r
576       # <b>Used in</b>::  <tt>#format</tt>, <tt>#paragraphs</tt>\r
577     def justify?\r
578       return @format_style == JUSTIFY\r
579     end\r
581       # The default implementation of #hyphenate_to implements\r
582       # SPLIT_CONTINUATION.\r
583     def hyphenate_to(word, size)\r
584       [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]]\r
585     end\r
587   private\r
588     def __do_split_word(word, size) #:nodoc:\r
589       [word[0 .. (size - 1)], word[size .. -1]]\r
590     end\r
592     def __format(to_wrap) #:nodoc:\r
593       words = to_wrap.split(/\s+/).compact\r
594       words.shift if words[0].nil? or words[0].empty?\r
595       to_wrap = []\r
597       abbrev = false\r
598       width = @columns - @first_indent - @left_margin - @right_margin\r
599       indent_str = ' ' * @first_indent\r
600       first_line = true\r
601       line = words.shift\r
602       abbrev = __is_abbrev(line) unless line.nil? || line.empty?\r
604       while w = words.shift\r
605         if (w.size + line.size < (width - 1)) ||\r
606            ((line !~ LEQ_RE || abbrev) && (w.size + line.size < width))\r
607           line << " " if (line =~ LEQ_RE) && (not abbrev)\r
608           line << " #{w}"\r
609         else\r
610           line, w = __do_break(line, w) if @nobreak\r
611           line, w = __do_hyphenate(line, w, width) if @hard_margins\r
612           if w.index(/\s+/)\r
613             w, *w2 = w.split(/\s+/)\r
614             words.unshift(w2)\r
615             words.flatten!\r
616           end\r
617           to_wrap << __make_line(line, indent_str, width, w.nil?) unless line.nil?\r
618           if first_line\r
619             first_line = false\r
620             width = @columns - @body_indent - @left_margin - @right_margin\r
621             indent_str = ' ' * @body_indent\r
622           end\r
623           line = w\r
624         end\r
626         abbrev = __is_abbrev(w) unless w.nil?\r
627       end\r
629       loop do\r
630         break if line.nil? or line.empty?\r
631         line, w = __do_hyphenate(line, w, width) if @hard_margins\r
632         to_wrap << __make_line(line, indent_str, width, w.nil?)\r
633         line = w\r
634       end\r
636       if (@tag_paragraph && (to_wrap.size > 0)) then\r
637         clr = %r{`(\w+)'}.match([caller(1)].flatten[0])[1]\r
638         clr = "" if clr.nil?\r
640         if ((not @tag_text[0].nil?) && (@tag_cur.size < 1) &&\r
641             (clr != "__paragraphs")) then\r
642           @tag_cur = @tag_text[0]\r
643         end\r
645         fchar = /(\S)/.match(to_wrap[0])[1]\r
646         white = to_wrap[0].index(fchar)\r
647         if ((white - @left_margin - 1) > @tag_cur.size) then\r
648           white = @tag_cur.size + @left_margin\r
649           to_wrap[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}")\r
650         else\r
651           to_wrap.unshift("#{' ' * @left_margin}#{@tag_cur}\n")\r
652         end\r
653       end\r
654       to_wrap.join('')\r
655     end\r
657       # format lines in text into paragraphs with each element of @wrap a\r
658       # paragraph; uses Text::Format.format for the formatting\r
659     def __paragraphs(to_wrap) #:nodoc:\r
660       if ((@first_indent == @body_indent) || @tag_paragraph) then\r
661         p_end = "\n"\r
662       else\r
663         p_end = ''\r
664       end\r
666       cnt = 0\r
667       ret = []\r
668       to_wrap.each do |tw|\r
669         @tag_cur = @tag_text[cnt] if @tag_paragraph\r
670         @tag_cur = '' if @tag_cur.nil?\r
671         line = __format(tw)\r
672         ret << "#{line}#{p_end}" if (not line.nil?) && (line.size > 0)\r
673         cnt += 1\r
674       end\r
676       ret[-1].chomp! unless ret.empty?\r
677       ret.join('')\r
678     end\r
680       # center text using spaces on left side to pad it out empty lines\r
681       # are preserved\r
682     def __center(to_center) #:nodoc:\r
683       tabs = 0\r
684       width = @columns - @left_margin - @right_margin\r
685       centered = []\r
686       to_center.each do |tc|\r
687         s = tc.strip\r
688         tabs = s.count("\t")\r
689         tabs = 0 if tabs.nil?\r
690         ct = ((width - s.size - (tabs * @tabstop) + tabs) / 2)\r
691         ct = (width - @left_margin - @right_margin) - ct\r
692         centered << "#{s.rjust(ct)}\n"\r
693       end\r
694       centered.join('')\r
695     end\r
697       # expand tabs to spaces should be similar to Text::Tabs::expand\r
698     def __expand(to_expand) #:nodoc:\r
699       expanded = []\r
700       to_expand.split("\n").each { |te| expanded << te.gsub(/\t/, ' ' * @tabstop) }\r
701       expanded.join('')\r
702     end\r
704     def __unexpand(to_unexpand) #:nodoc:\r
705       unexpanded = []\r
706       to_unexpand.split("\n").each { |tu| unexpanded << tu.gsub(/ {#{@tabstop}}/, "\t") }\r
707       unexpanded.join('')\r
708     end\r
710     def __is_abbrev(word) #:nodoc:\r
711         # remove period if there is one.\r
712       w = word.gsub(/\.$/, '') unless word.nil?\r
713       return true if (!@extra_space || ABBREV.include?(w) || @abbreviations.include?(w))\r
714       false\r
715     end\r
717     def __make_line(line, indent, width, last = false) #:nodoc:\r
718       lmargin = " " * @left_margin\r
719       fill = " " * (width - line.size) if right_fill? && (line.size <= width)\r
721       if (justify? && ((not line.nil?) && (not line.empty?)) && line =~ /\S+\s+\S+/ && !last)\r
722         spaces = width - line.size\r
723         words = line.split(/(\s+)/)\r
724         ws = spaces / (words.size / 2)\r
725         spaces = spaces % (words.size / 2) if ws > 0\r
726         words.reverse.each do |rw|\r
727           next if (rw =~ /^\S/)\r
728           rw.sub!(/^/, " " * ws)\r
729           next unless (spaces > 0)\r
730           rw.sub!(/^/, " ")\r
731           spaces -= 1\r
732         end\r
733         line = words.join('')\r
734       end\r
735       line = "#{lmargin}#{indent}#{line}#{fill}\n" unless line.nil?\r
736       if right_align? && (not line.nil?)\r
737         line.sub(/^/, " " * (@columns - @right_margin - (line.size - 1)))\r
738       else\r
739         line\r
740       end\r
741     end\r
743     def __do_hyphenate(line, next_line, width) #:nodoc:\r
744       rline = line.dup rescue line\r
745       rnext = next_line.dup rescue next_line\r
746       loop do\r
747         if rline.size == width\r
748           break\r
749         elsif rline.size > width\r
750           words = rline.strip.split(/\s+/)\r
751           word = words[-1].dup\r
752           size = width - rline.size + word.size\r
753           if (size <= 0)\r
754             words[-1] = nil\r
755             rline = words.join(' ').strip\r
756             rnext = "#{word} #{rnext}".strip\r
757             next\r
758           end\r
760           first = rest = nil\r
762           if ((@split_rules & SPLIT_HYPHENATION) != 0)\r
763             if @hyphenator_arity == 2\r
764               first, rest = @hyphenator.hyphenate_to(word, size)\r
765             else\r
766               first, rest = @hyphenator.hyphenate_to(word, size, self)\r
767             end\r
768           end\r
770           if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil?\r
771             first, rest = self.hyphenate_to(word, size)\r
772           end\r
774           if ((@split_rules & SPLIT_FIXED) != 0) and first.nil?\r
775             first.nil? or @split_rules == SPLIT_FIXED\r
776             first, rest = __do_split_word(word, size)\r
777           end\r
779           if first.nil?\r
780             words[-1] = nil\r
781             rest = word\r
782           else\r
783             words[-1] = first\r
784             @split_words << SplitWord.new(word, first, rest)\r
785           end\r
786           rline = words.join(' ').strip\r
787           rnext = "#{rest} #{rnext}".strip\r
788           break\r
789         else\r
790           break if rnext.nil? or rnext.empty? or rline.nil? or rline.empty?\r
791           words = rnext.split(/\s+/)\r
792           word = words.shift\r
793           size = width - rline.size - 1\r
795           if (size <= 0)\r
796             rnext = "#{word} #{words.join(' ')}".strip\r
797             break\r
798           end\r
800           first = rest = nil\r
802           if ((@split_rules & SPLIT_HYPHENATION) != 0)\r
803             if @hyphenator_arity == 2\r
804               first, rest = @hyphenator.hyphenate_to(word, size)\r
805             else\r
806               first, rest = @hyphenator.hyphenate_to(word, size, self)\r
807             end\r
808           end\r
810           first, rest = self.hyphenate_to(word, size) if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil?\r
812           first, rest = __do_split_word(word, size) if ((@split_rules & SPLIT_FIXED) != 0) and first.nil?\r
814           if (rline.size + (first ? first.size : 0)) < width\r
815             @split_words << SplitWord.new(word, first, rest)\r
816             rline = "#{rline} #{first}".strip\r
817             rnext = "#{rest} #{words.join(' ')}".strip\r
818           end\r
819           break\r
820         end\r
821       end\r
822       [rline, rnext]\r
823     end\r
825     def __do_break(line, next_line) #:nodoc:\r
826       no_brk = false\r
827       words = []\r
828       words = line.split(/\s+/) unless line.nil?\r
829       last_word = words[-1]\r
831       @nobreak_regex.each { |k, v| no_brk = ((last_word =~ /#{k}/) and (next_line =~ /#{v}/)) }\r
833       if no_brk && words.size > 1\r
834         i = words.size\r
835         while i > 0\r
836           no_brk = false\r
837           @nobreak_regex.each { |k, v| no_brk = ((words[i + 1] =~ /#{k}/) && (words[i] =~ /#{v}/)) }\r
838           i -= 1\r
839           break if not no_brk\r
840         end\r
841         if i > 0\r
842           l = brk_re(i).match(line)\r
843           line.sub!(brk_re(i), l[1])\r
844           next_line = "#{l[2]} #{next_line}"\r
845           line.sub!(/\s+$/, '')\r
846         end\r
847       end\r
848       [line, next_line]\r
849     end\r
851     def __create(arg = nil, &block) #:nodoc:\r
852         # Format::Text.new(text-to-wrap)\r
853       @text = arg unless arg.nil?\r
854         # Defaults\r
855       @columns          = 72\r
856       @tabstop          = 8\r
857       @first_indent     = 4\r
858       @body_indent      = 0\r
859       @format_style     = LEFT_ALIGN\r
860       @left_margin      = 0\r
861       @right_margin     = 0\r
862       @extra_space      = false\r
863       @text             = Array.new if @text.nil?\r
864       @tag_paragraph    = false\r
865       @tag_text         = Array.new\r
866       @tag_cur          = ""\r
867       @abbreviations    = Array.new\r
868       @nobreak          = false\r
869       @nobreak_regex    = Hash.new\r
870       @split_words      = Array.new\r
871       @hard_margins     = false\r
872       @split_rules      = SPLIT_FIXED\r
873       @hyphenator       = self\r
874       @hyphenator_arity = self.method(:hyphenate_to).arity\r
876       instance_eval(&block) unless block.nil?\r
877     end\r
879   public\r
880       # Formats text into a nice paragraph format. The text is separated\r
881       # into words and then reassembled a word at a time using the settings\r
882       # of this Format object. If a word is larger than the number of\r
883       # columns available for formatting, then that word will appear on the\r
884       # line by itself.\r
885       #\r
886       # If +to_wrap+ is +nil+, then the value of <tt>#text</tt> will be\r
887       # worked on.\r
888     def format(to_wrap = nil)\r
889       to_wrap = @text if to_wrap.nil?\r
890       if to_wrap.class == Array\r
891         __format(to_wrap[0])\r
892       else\r
893         __format(to_wrap)\r
894       end\r
895     end\r
897       # Considers each element of text (provided or internal) as a paragraph.\r
898       # If <tt>#first_indent</tt> is the same as <tt>#body_indent</tt>, then\r
899       # paragraphs will be separated by a single empty line in the result;\r
900       # otherwise, the paragraphs will follow immediately after each other.\r
901       # Uses <tt>#format</tt> to do the heavy lifting.\r
902     def paragraphs(to_wrap = nil)\r
903       to_wrap = @text if to_wrap.nil?\r
904       __paragraphs([to_wrap].flatten)\r
905     end\r
907       # Centers the text, preserving empty lines and tabs.\r
908     def center(to_center = nil)\r
909       to_center = @text if to_center.nil?\r
910       __center([to_center].flatten)\r
911     end\r
913       # Replaces all tab characters in the text with <tt>#tabstop</tt> spaces.\r
914     def expand(to_expand = nil)\r
915       to_expand = @text if to_expand.nil?\r
916       if to_expand.class == Array\r
917         to_expand.collect { |te| __expand(te) }\r
918       else\r
919         __expand(to_expand)\r
920       end\r
921     end\r
923       # Replaces all occurrences of <tt>#tabstop</tt> consecutive spaces\r
924       # with a tab character.\r
925     def unexpand(to_unexpand = nil)\r
926       to_unexpand = @text if to_unexpand.nil?\r
927       if to_unexpand.class == Array\r
928         to_unexpand.collect { |te| v << __unexpand(te) }\r
929       else\r
930         __unexpand(to_unexpand)\r
931       end\r
932     end\r
934       # This constructor takes advantage of a technique for Ruby object\r
935       # construction introduced by Andy Hunt and Dave Thomas (see reference),\r
936       # where optional values are set using commands in a block.\r
937       #\r
938       #   Text::Format.new {\r
939       #       columns         = 72\r
940       #       left_margin     = 0\r
941       #       right_margin    = 0\r
942       #       first_indent    = 4\r
943       #       body_indent     = 0\r
944       #       format_style    = Text::Format::LEFT_ALIGN\r
945       #       extra_space     = false\r
946       #       abbreviations   = {}\r
947       #       tag_paragraph   = false\r
948       #       tag_text        = []\r
949       #       nobreak         = false\r
950       #       nobreak_regex   = {}\r
951       #       tabstop         = 8\r
952       #       text            = nil\r
953       #   }\r
954       #\r
955       # As shown above, +arg+ is optional. If +arg+ is specified and is a\r
956       # +String+, then arg is used as the default value of <tt>#text</tt>.\r
957       # Alternately, an existing Text::Format object can be used or a Hash can\r
958       # be used. With all forms, a block can be specified.\r
959       #\r
960       # *Reference*:: "Object Construction and Blocks"\r
961       #               <http://www.pragmaticprogrammer.com/ruby/articles/insteval.html>\r
962       #\r
963     def initialize(arg = nil, &block)\r
964       case arg\r
965       when Text::Format\r
966         __create(arg.text) do\r
967           @columns        = arg.columns\r
968           @tabstop        = arg.tabstop\r
969           @first_indent   = arg.first_indent\r
970           @body_indent    = arg.body_indent\r
971           @format_style   = arg.format_style\r
972           @left_margin    = arg.left_margin\r
973           @right_margin   = arg.right_margin\r
974           @extra_space    = arg.extra_space\r
975           @tag_paragraph  = arg.tag_paragraph\r
976           @tag_text       = arg.tag_text\r
977           @abbreviations  = arg.abbreviations\r
978           @nobreak        = arg.nobreak\r
979           @nobreak_regex  = arg.nobreak_regex\r
980           @text           = arg.text\r
981           @hard_margins   = arg.hard_margins\r
982           @split_words    = arg.split_words\r
983           @split_rules    = arg.split_rules\r
984           @hyphenator     = arg.hyphenator\r
985         end\r
986         instance_eval(&block) unless block.nil?\r
987       when Hash\r
988         __create do\r
989           @columns       = arg[:columns]       || arg['columns']       || @columns\r
990           @tabstop       = arg[:tabstop]       || arg['tabstop']       || @tabstop\r
991           @first_indent  = arg[:first_indent]  || arg['first_indent']  || @first_indent\r
992           @body_indent   = arg[:body_indent]   || arg['body_indent']   || @body_indent\r
993           @format_style  = arg[:format_style]  || arg['format_style']  || @format_style\r
994           @left_margin   = arg[:left_margin]   || arg['left_margin']   || @left_margin\r
995           @right_margin  = arg[:right_margin]  || arg['right_margin']  || @right_margin\r
996           @extra_space   = arg[:extra_space]   || arg['extra_space']   || @extra_space\r
997           @text          = arg[:text]          || arg['text']          || @text\r
998           @tag_paragraph = arg[:tag_paragraph] || arg['tag_paragraph'] || @tag_paragraph\r
999           @tag_text      = arg[:tag_text]      || arg['tag_text']      || @tag_text\r
1000           @abbreviations = arg[:abbreviations] || arg['abbreviations'] || @abbreviations\r
1001           @nobreak       = arg[:nobreak]       || arg['nobreak']       || @nobreak\r
1002           @nobreak_regex = arg[:nobreak_regex] || arg['nobreak_regex'] || @nobreak_regex\r
1003           @hard_margins  = arg[:hard_margins]  || arg['hard_margins']  || @hard_margins\r
1004           @split_rules   = arg[:split_rules] || arg['split_rules'] || @split_rules\r
1005           @hyphenator    = arg[:hyphenator] || arg['hyphenator'] || @hyphenator\r
1006         end\r
1007         instance_eval(&block) unless block.nil?\r
1008       when String\r
1009         __create(arg, &block)\r
1010       when NilClass\r
1011         __create(&block)\r
1012       else\r
1013         raise TypeError\r
1014       end\r
1015     end\r
1016   end\r
1017 end\r
1019 if __FILE__ == $0\r
1020   require 'test/unit'\r
1022   class TestText__Format < Test::Unit::TestCase #:nodoc:\r
1023     attr_accessor :format_o\r
1025     GETTYSBURG = <<-'EOS'\r
1026     Four score and seven years ago our fathers brought forth on this\r
1027     continent a new nation, conceived in liberty and dedicated to the\r
1028     proposition that all men are created equal. Now we are engaged in\r
1029     a great civil war, testing whether that nation or any nation so\r
1030     conceived and so dedicated can long endure. We are met on a great\r
1031     battlefield of that war. We have come to dedicate a portion of\r
1032     that field as a final resting-place for those who here gave their\r
1033     lives that that nation might live. It is altogether fitting and\r
1034     proper that we should do this. But in a larger sense, we cannot\r
1035     dedicate, we cannot consecrate, we cannot hallow this ground.\r
1036     The brave men, living and dead who struggled here have consecrated\r
1037     it far above our poor power to add or detract. The world will\r
1038     little note nor long remember what we say here, but it can never\r
1039     forget what they did here. It is for us the living rather to be\r
1040     dedicated here to the unfinished work which they who fought here\r
1041     have thus far so nobly advanced. It is rather for us to be here\r
1042     dedicated to the great task remaining before us--that from these\r
1043     honored dead we take increased devotion to that cause for which\r
1044     they gave the last full measure of devotion--that we here highly\r
1045     resolve that these dead shall not have died in vain, that this\r
1046     nation under God shall have a new birth of freedom, and that\r
1047     government of the people, by the people, for the people shall\r
1048     not perish from the earth.\r
1050             -- Pres. Abraham Lincoln, 19 November 1863\r
1051     EOS\r
1053     FIVE_COL = "Four \nscore\nand s\neven \nyears\nago o\nur fa\nthers\nbroug\nht fo\nrth o\nn thi\ns con\ntinen\nt a n\new na\ntion,\nconce\nived \nin li\nberty\nand d\nedica\nted t\no the\npropo\nsitio\nn tha\nt all\nmen a\nre cr\neated\nequal\n. Now\nwe ar\ne eng\naged \nin a \ngreat\ncivil\nwar, \ntesti\nng wh\nether\nthat \nnatio\nn or \nany n\nation\nso co\nnceiv\ned an\nd so \ndedic\nated \ncan l\nong e\nndure\n. We \nare m\net on\na gre\nat ba\nttlef\nield \nof th\nat wa\nr. We\nhave \ncome \nto de\ndicat\ne a p\nortio\nn of \nthat \nfield\nas a \nfinal\nresti\nng-pl\nace f\nor th\nose w\nho he\nre ga\nve th\neir l\nives \nthat \nthat \nnatio\nn mig\nht li\nve. I\nt is \naltog\nether\nfitti\nng an\nd pro\nper t\nhat w\ne sho\nuld d\no thi\ns. Bu\nt in \na lar\nger s\nense,\nwe ca\nnnot \ndedic\nate, \nwe ca\nnnot \nconse\ncrate\n, we \ncanno\nt hal\nlow t\nhis g\nround\n. The\nbrave\nmen, \nlivin\ng and\ndead \nwho s\ntrugg\nled h\nere h\nave c\nonsec\nrated\nit fa\nr abo\nve ou\nr poo\nr pow\ner to\nadd o\nr det\nract.\nThe w\norld \nwill \nlittl\ne not\ne nor\nlong \nremem\nber w\nhat w\ne say\nhere,\nbut i\nt can\nnever\nforge\nt wha\nt the\ny did\nhere.\nIt is\nfor u\ns the\nlivin\ng rat\nher t\no be \ndedic\nated \nhere \nto th\ne unf\ninish\ned wo\nrk wh\nich t\nhey w\nho fo\nught \nhere \nhave \nthus \nfar s\no nob\nly ad\nvance\nd. It\nis ra\nther \nfor u\ns to \nbe he\nre de\ndicat\ned to\nthe g\nreat \ntask \nremai\nning \nbefor\ne us-\n-that\nfrom \nthese\nhonor\ned de\nad we\ntake \nincre\nased \ndevot\nion t\no tha\nt cau\nse fo\nr whi\nch th\ney ga\nve th\ne las\nt ful\nl mea\nsure \nof de\nvotio\nn--th\nat we\nhere \nhighl\ny res\nolve \nthat \nthese\ndead \nshall\nnot h\nave d\nied i\nn vai\nn, th\nat th\nis na\ntion \nunder\nGod s\nhall \nhave \na new\nbirth\nof fr\needom\n, and\nthat \ngover\nnment\nof th\ne peo\nple, \nby th\ne peo\nple, \nfor t\nhe pe\nople \nshall\nnot p\nerish\nfrom \nthe e\narth.\n-- Pr\nes. A\nbraha\nm Lin\ncoln,\n19 No\nvembe\nr 186\n3    \n"\r
1055     FIVE_CNT = "Four \nscore\nand  \nseven\nyears\nago  \nour  \nfath\\\ners  \nbrou\\\nght  \nforth\non t\\\nhis  \ncont\\\ninent\na new\nnati\\\non,  \nconc\\\neived\nin l\\\niber\\\nty a\\\nnd d\\\nedic\\\nated \nto t\\\nhe p\\\nropo\\\nsiti\\\non t\\\nhat  \nall  \nmen  \nare  \ncrea\\\nted  \nequa\\\nl. N\\\now we\nare  \nenga\\\nged  \nin a \ngreat\ncivil\nwar, \ntest\\\ning  \nwhet\\\nher  \nthat \nnati\\\non or\nany  \nnati\\\non so\nconc\\\neived\nand  \nso d\\\nedic\\\nated \ncan  \nlong \nendu\\\nre.  \nWe a\\\nre m\\\net on\na gr\\\neat  \nbatt\\\nlefi\\\neld  \nof t\\\nhat  \nwar. \nWe h\\\nave  \ncome \nto d\\\nedic\\\nate a\nport\\\nion  \nof t\\\nhat  \nfield\nas a \nfinal\nrest\\\ning-\\\nplace\nfor  \nthose\nwho  \nhere \ngave \ntheir\nlives\nthat \nthat \nnati\\\non m\\\night \nlive.\nIt is\nalto\\\ngeth\\\ner f\\\nitti\\\nng a\\\nnd p\\\nroper\nthat \nwe s\\\nhould\ndo t\\\nhis. \nBut  \nin a \nlarg\\\ner s\\\nense,\nwe c\\\nannot\ndedi\\\ncate,\nwe c\\\nannot\ncons\\\necra\\\nte,  \nwe c\\\nannot\nhall\\\now t\\\nhis  \ngrou\\\nnd.  \nThe  \nbrave\nmen, \nlivi\\\nng a\\\nnd d\\\nead  \nwho  \nstru\\\nggled\nhere \nhave \ncons\\\necra\\\nted  \nit f\\\nar a\\\nbove \nour  \npoor \npower\nto a\\\ndd or\ndetr\\\nact. \nThe  \nworld\nwill \nlitt\\\nle n\\\note  \nnor  \nlong \nreme\\\nmber \nwhat \nwe s\\\nay h\\\nere, \nbut  \nit c\\\nan n\\\never \nforg\\\net w\\\nhat  \nthey \ndid  \nhere.\nIt is\nfor  \nus t\\\nhe l\\\niving\nrath\\\ner to\nbe d\\\nedic\\\nated \nhere \nto t\\\nhe u\\\nnfin\\\nished\nwork \nwhich\nthey \nwho  \nfoug\\\nht h\\\nere  \nhave \nthus \nfar  \nso n\\\nobly \nadva\\\nnced.\nIt is\nrath\\\ner f\\\nor us\nto be\nhere \ndedi\\\ncated\nto t\\\nhe g\\\nreat \ntask \nrema\\\nining\nbefo\\\nre u\\\ns--t\\\nhat  \nfrom \nthese\nhono\\\nred  \ndead \nwe t\\\nake  \nincr\\\neased\ndevo\\\ntion \nto t\\\nhat  \ncause\nfor  \nwhich\nthey \ngave \nthe  \nlast \nfull \nmeas\\\nure  \nof d\\\nevot\\\nion-\\\n-that\nwe h\\\nere  \nhigh\\\nly r\\\nesol\\\nve t\\\nhat  \nthese\ndead \nshall\nnot  \nhave \ndied \nin v\\\nain, \nthat \nthis \nnati\\\non u\\\nnder \nGod  \nshall\nhave \na new\nbirth\nof f\\\nreed\\\nom,  \nand  \nthat \ngove\\\nrnme\\\nnt of\nthe  \npeop\\\nle,  \nby t\\\nhe p\\\neopl\\\ne, f\\\nor t\\\nhe p\\\neople\nshall\nnot  \nperi\\\nsh f\\\nrom  \nthe  \neart\\\nh. --\nPres.\nAbra\\\nham  \nLinc\\\noln, \n19 N\\\novem\\\nber  \n1863 \n"\r
1057       # Tests both abbreviations and abbreviations=\r
1058     def test_abbreviations\r
1059       abbr = ["    Pres. Abraham Lincoln\n", "    Pres.  Abraham Lincoln\n"]\r
1060       assert_nothing_raised { @format_o = Text::Format.new }\r
1061       assert_equal([], @format_o.abbreviations)\r
1062       assert_nothing_raised { @format_o.abbreviations = [ 'foo', 'bar' ] }\r
1063       assert_equal([ 'foo', 'bar' ], @format_o.abbreviations)\r
1064       assert_equal(abbr[0], @format_o.format(abbr[0]))\r
1065       assert_nothing_raised { @format_o.extra_space = true }\r
1066       assert_equal(abbr[1], @format_o.format(abbr[0]))\r
1067       assert_nothing_raised { @format_o.abbreviations = [ "Pres" ] }\r
1068       assert_equal([ "Pres" ], @format_o.abbreviations)\r
1069       assert_equal(abbr[0], @format_o.format(abbr[0]))\r
1070       assert_nothing_raised { @format_o.extra_space = false }\r
1071       assert_equal(abbr[0], @format_o.format(abbr[0]))\r
1072     end\r
1074       # Tests both body_indent and body_indent=\r
1075     def test_body_indent\r
1076       assert_nothing_raised { @format_o = Text::Format.new }\r
1077       assert_equal(0, @format_o.body_indent)\r
1078       assert_nothing_raised { @format_o.body_indent = 7 }\r
1079       assert_equal(7, @format_o.body_indent)\r
1080       assert_nothing_raised { @format_o.body_indent = -3 }\r
1081       assert_equal(3, @format_o.body_indent)\r
1082       assert_nothing_raised { @format_o.body_indent = "9" }\r
1083       assert_equal(9, @format_o.body_indent)\r
1084       assert_nothing_raised { @format_o.body_indent = "-2" }\r
1085       assert_equal(2, @format_o.body_indent)\r
1086       assert_match(/^  [^ ]/, @format_o.format(GETTYSBURG).split("\n")[1])\r
1087     end\r
1089       # Tests both columns and columns=\r
1090     def test_columns\r
1091       assert_nothing_raised { @format_o = Text::Format.new }\r
1092       assert_equal(72, @format_o.columns)\r
1093       assert_nothing_raised { @format_o.columns = 7 }\r
1094       assert_equal(7, @format_o.columns)\r
1095       assert_nothing_raised { @format_o.columns = -3 }\r
1096       assert_equal(3, @format_o.columns)\r
1097       assert_nothing_raised { @format_o.columns = "9" }\r
1098       assert_equal(9, @format_o.columns)\r
1099       assert_nothing_raised { @format_o.columns = "-2" }\r
1100       assert_equal(2, @format_o.columns)\r
1101       assert_nothing_raised { @format_o.columns = 40 }\r
1102       assert_equal(40, @format_o.columns)\r
1103       assert_match(/this continent$/,\r
1104                    @format_o.format(GETTYSBURG).split("\n")[1])\r
1105     end\r
1107       # Tests both extra_space and extra_space=\r
1108     def test_extra_space\r
1109       assert_nothing_raised { @format_o = Text::Format.new }\r
1110       assert(!@format_o.extra_space)\r
1111       assert_nothing_raised { @format_o.extra_space = true }\r
1112       assert(@format_o.extra_space)\r
1113         # The behaviour of extra_space is tested in test_abbreviations. There\r
1114         # is no need to reproduce it here.\r
1115     end\r
1117       # Tests both first_indent and first_indent=\r
1118     def test_first_indent\r
1119       assert_nothing_raised { @format_o = Text::Format.new }\r
1120       assert_equal(4, @format_o.first_indent)\r
1121       assert_nothing_raised { @format_o.first_indent = 7 }\r
1122       assert_equal(7, @format_o.first_indent)\r
1123       assert_nothing_raised { @format_o.first_indent = -3 }\r
1124       assert_equal(3, @format_o.first_indent)\r
1125       assert_nothing_raised { @format_o.first_indent = "9" }\r
1126       assert_equal(9, @format_o.first_indent)\r
1127       assert_nothing_raised { @format_o.first_indent = "-2" }\r
1128       assert_equal(2, @format_o.first_indent)\r
1129       assert_match(/^  [^ ]/, @format_o.format(GETTYSBURG).split("\n")[0])\r
1130     end\r
1132     def test_format_style\r
1133       assert_nothing_raised { @format_o = Text::Format.new }\r
1134       assert_equal(Text::Format::LEFT_ALIGN, @format_o.format_style)\r
1135       assert_match(/^November 1863$/,\r
1136                    @format_o.format(GETTYSBURG).split("\n")[-1])\r
1137       assert_nothing_raised {\r
1138         @format_o.format_style = Text::Format::RIGHT_ALIGN\r
1139       }\r
1140       assert_equal(Text::Format::RIGHT_ALIGN, @format_o.format_style)\r
1141       assert_match(/^ +November 1863$/,\r
1142                    @format_o.format(GETTYSBURG).split("\n")[-1])\r
1143       assert_nothing_raised {\r
1144         @format_o.format_style = Text::Format::RIGHT_FILL\r
1145       }\r
1146       assert_equal(Text::Format::RIGHT_FILL, @format_o.format_style)\r
1147       assert_match(/^November 1863 +$/,\r
1148                    @format_o.format(GETTYSBURG).split("\n")[-1])\r
1149       assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY }\r
1150       assert_equal(Text::Format::JUSTIFY, @format_o.format_style)\r
1151       assert_match(/^of freedom, and that government of the people, by the  people,  for  the$/,\r
1152                    @format_o.format(GETTYSBURG).split("\n")[-3])\r
1153       assert_raises(ArgumentError) { @format_o.format_style = 33 }\r
1154     end\r
1156     def test_tag_paragraph\r
1157       assert_nothing_raised { @format_o = Text::Format.new }\r
1158       assert(!@format_o.tag_paragraph)\r
1159       assert_nothing_raised { @format_o.tag_paragraph = true }\r
1160       assert(@format_o.tag_paragraph)\r
1161       assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]),\r
1162                        Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG]))\r
1163     end\r
1165     def test_tag_text\r
1166       assert_nothing_raised { @format_o = Text::Format.new }\r
1167       assert_equal([], @format_o.tag_text)\r
1168       assert_equal(@format_o.format(GETTYSBURG),\r
1169                    Text::Format.new.format(GETTYSBURG))\r
1170       assert_nothing_raised {\r
1171         @format_o.tag_paragraph = true\r
1172         @format_o.tag_text = ["Gettysburg Address", "---"]\r
1173       }\r
1174       assert_not_equal(@format_o.format(GETTYSBURG),\r
1175                        Text::Format.new.format(GETTYSBURG))\r
1176       assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]),\r
1177                        Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG]))\r
1178       assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG,\r
1179                                              GETTYSBURG]),\r
1180                        Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG,\r
1181                                                     GETTYSBURG]))\r
1182     end\r
1184     def test_justify?\r
1185       assert_nothing_raised { @format_o = Text::Format.new }\r
1186       assert(!@format_o.justify?)\r
1187       assert_nothing_raised {\r
1188         @format_o.format_style = Text::Format::RIGHT_ALIGN\r
1189       }\r
1190       assert(!@format_o.justify?)\r
1191       assert_nothing_raised {\r
1192         @format_o.format_style = Text::Format::RIGHT_FILL\r
1193       }\r
1194       assert(!@format_o.justify?)\r
1195       assert_nothing_raised {\r
1196         @format_o.format_style = Text::Format::JUSTIFY\r
1197       }\r
1198       assert(@format_o.justify?)\r
1199         # The format testing is done in test_format_style\r
1200     end\r
1202     def test_left_align?\r
1203       assert_nothing_raised { @format_o = Text::Format.new }\r
1204       assert(@format_o.left_align?)\r
1205       assert_nothing_raised {\r
1206         @format_o.format_style = Text::Format::RIGHT_ALIGN\r
1207       }\r
1208       assert(!@format_o.left_align?)\r
1209       assert_nothing_raised {\r
1210         @format_o.format_style = Text::Format::RIGHT_FILL\r
1211       }\r
1212       assert(!@format_o.left_align?)\r
1213       assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY }\r
1214       assert(!@format_o.left_align?)\r
1215         # The format testing is done in test_format_style\r
1216     end\r
1218     def test_left_margin\r
1219       assert_nothing_raised { @format_o = Text::Format.new }\r
1220       assert_equal(0, @format_o.left_margin)\r
1221       assert_nothing_raised { @format_o.left_margin = -3 }\r
1222       assert_equal(3, @format_o.left_margin)\r
1223       assert_nothing_raised { @format_o.left_margin = "9" }\r
1224       assert_equal(9, @format_o.left_margin)\r
1225       assert_nothing_raised { @format_o.left_margin = "-2" }\r
1226       assert_equal(2, @format_o.left_margin)\r
1227       assert_nothing_raised { @format_o.left_margin = 7 }\r
1228       assert_equal(7, @format_o.left_margin)\r
1229       assert_nothing_raised {\r
1230         ft = @format_o.format(GETTYSBURG).split("\n")\r
1231         assert_match(/^ {11}Four score/, ft[0])\r
1232         assert_match(/^ {7}November/, ft[-1])\r
1233       }\r
1234     end\r
1236     def test_hard_margins\r
1237       assert_nothing_raised { @format_o = Text::Format.new }\r
1238       assert(!@format_o.hard_margins)\r
1239       assert_nothing_raised {\r
1240         @format_o.hard_margins = true\r
1241         @format_o.columns = 5\r
1242         @format_o.first_indent = 0\r
1243         @format_o.format_style = Text::Format::RIGHT_FILL\r
1244       }\r
1245       assert(@format_o.hard_margins)\r
1246       assert_equal(FIVE_COL, @format_o.format(GETTYSBURG))\r
1247       assert_nothing_raised {\r
1248         @format_o.split_rules |= Text::Format::SPLIT_CONTINUATION\r
1249         assert_equal(Text::Format::SPLIT_CONTINUATION_FIXED,\r
1250                      @format_o.split_rules)\r
1251       }\r
1252       assert_equal(FIVE_CNT, @format_o.format(GETTYSBURG))\r
1253     end\r
1255       # Tests both nobreak and nobreak_regex, since one is only useful\r
1256       # with the other.\r
1257     def test_nobreak\r
1258       assert_nothing_raised { @format_o = Text::Format.new }\r
1259       assert(!@format_o.nobreak)\r
1260       assert(@format_o.nobreak_regex.empty?)\r
1261       assert_nothing_raised {\r
1262         @format_o.nobreak = true\r
1263         @format_o.nobreak_regex = { '^this$' => '^continent$' }\r
1264         @format_o.columns = 77\r
1265       }\r
1266       assert(@format_o.nobreak)\r
1267       assert_equal({ '^this$' => '^continent$' }, @format_o.nobreak_regex)\r
1268       assert_match(/^this continent/,\r
1269                    @format_o.format(GETTYSBURG).split("\n")[1])\r
1270     end\r
1272     def test_right_align?\r
1273       assert_nothing_raised { @format_o = Text::Format.new }\r
1274       assert(!@format_o.right_align?)\r
1275       assert_nothing_raised {\r
1276         @format_o.format_style = Text::Format::RIGHT_ALIGN\r
1277       }\r
1278       assert(@format_o.right_align?)\r
1279       assert_nothing_raised {\r
1280         @format_o.format_style = Text::Format::RIGHT_FILL\r
1281       }\r
1282       assert(!@format_o.right_align?)\r
1283       assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY }\r
1284       assert(!@format_o.right_align?)\r
1285         # The format testing is done in test_format_style\r
1286     end\r
1288     def test_right_fill?\r
1289       assert_nothing_raised { @format_o = Text::Format.new }\r
1290       assert(!@format_o.right_fill?)\r
1291       assert_nothing_raised {\r
1292         @format_o.format_style = Text::Format::RIGHT_ALIGN\r
1293       }\r
1294       assert(!@format_o.right_fill?)\r
1295       assert_nothing_raised {\r
1296         @format_o.format_style = Text::Format::RIGHT_FILL\r
1297       }\r
1298       assert(@format_o.right_fill?)\r
1299       assert_nothing_raised {\r
1300         @format_o.format_style = Text::Format::JUSTIFY\r
1301       }\r
1302       assert(!@format_o.right_fill?)\r
1303         # The format testing is done in test_format_style\r
1304     end\r
1306     def test_right_margin\r
1307       assert_nothing_raised { @format_o = Text::Format.new }\r
1308       assert_equal(0, @format_o.right_margin)\r
1309       assert_nothing_raised { @format_o.right_margin = -3 }\r
1310       assert_equal(3, @format_o.right_margin)\r
1311       assert_nothing_raised { @format_o.right_margin = "9" }\r
1312       assert_equal(9, @format_o.right_margin)\r
1313       assert_nothing_raised { @format_o.right_margin = "-2" }\r
1314       assert_equal(2, @format_o.right_margin)\r
1315       assert_nothing_raised { @format_o.right_margin = 7 }\r
1316       assert_equal(7, @format_o.right_margin)\r
1317       assert_nothing_raised {\r
1318         ft = @format_o.format(GETTYSBURG).split("\n")\r
1319         assert_match(/^ {4}Four score.*forth on$/, ft[0])\r
1320         assert_match(/^November/, ft[-1])\r
1321       }\r
1322     end\r
1324     def test_tabstop\r
1325       assert_nothing_raised { @format_o = Text::Format.new }\r
1326       assert_equal(8, @format_o.tabstop)\r
1327       assert_nothing_raised { @format_o.tabstop = 7 }\r
1328       assert_equal(7, @format_o.tabstop)\r
1329       assert_nothing_raised { @format_o.tabstop = -3 }\r
1330       assert_equal(3, @format_o.tabstop)\r
1331       assert_nothing_raised { @format_o.tabstop = "9" }\r
1332       assert_equal(9, @format_o.tabstop)\r
1333       assert_nothing_raised { @format_o.tabstop = "-2" }\r
1334       assert_equal(2, @format_o.tabstop)\r
1335     end\r
1337     def test_text\r
1338       assert_nothing_raised { @format_o = Text::Format.new }\r
1339       assert_equal([], @format_o.text)\r
1340       assert_nothing_raised { @format_o.text = "Test Text" }\r
1341       assert_equal("Test Text", @format_o.text)\r
1342       assert_nothing_raised { @format_o.text = ["Line 1", "Line 2"] }\r
1343       assert_equal(["Line 1", "Line 2"], @format_o.text)\r
1344     end\r
1346     def test_s_new\r
1347           # new(NilClass) { block }\r
1348       assert_nothing_raised do\r
1349         @format_o = Text::Format.new {\r
1350           self.text = "Test 1, 2, 3"\r
1351         }\r
1352       end\r
1353       assert_equal("Test 1, 2, 3", @format_o.text)\r
1355         # new(Hash Symbols)\r
1356       assert_nothing_raised { @format_o = Text::Format.new(:columns => 72) }\r
1357       assert_equal(72, @format_o.columns)\r
1359         # new(Hash String)\r
1360       assert_nothing_raised { @format_o = Text::Format.new('columns' => 72) }\r
1361       assert_equal(72, @format_o.columns)\r
1363         # new(Hash) { block }\r
1364       assert_nothing_raised do\r
1365         @format_o = Text::Format.new('columns' => 80) {\r
1366           self.text = "Test 4, 5, 6"\r
1367         }\r
1368       end\r
1369       assert_equal("Test 4, 5, 6", @format_o.text)\r
1370       assert_equal(80, @format_o.columns)\r
1372         # new(Text::Format)\r
1373       assert_nothing_raised do\r
1374         fo = Text::Format.new(@format_o)\r
1375         assert(fo == @format_o)\r
1376       end\r
1378         # new(Text::Format) { block }\r
1379       assert_nothing_raised do\r
1380         fo = Text::Format.new(@format_o) { self.columns = 79 }\r
1381         assert(fo != @format_o)\r
1382       end\r
1384           # new(String)\r
1385       assert_nothing_raised { @format_o = Text::Format.new("Test A, B, C") }\r
1386       assert_equal("Test A, B, C", @format_o.text)\r
1388           # new(String) { block }\r
1389       assert_nothing_raised do\r
1390         @format_o = Text::Format.new("Test X, Y, Z") { self.columns = -5 }\r
1391       end\r
1392       assert_equal("Test X, Y, Z", @format_o.text)\r
1393       assert_equal(5, @format_o.columns)\r
1394     end\r
1396     def test_center\r
1397       assert_nothing_raised { @format_o = Text::Format.new }\r
1398       assert_nothing_raised do\r
1399         ct = @format_o.center(GETTYSBURG.split("\n")).split("\n")\r
1400         assert_match(/^    Four score and seven years ago our fathers brought forth on this/, ct[0])\r
1401         assert_match(/^                       not perish from the earth./, ct[-3])\r
1402       end\r
1403     end\r
1405     def test_expand\r
1406       assert_nothing_raised { @format_o = Text::Format.new }\r
1407       assert_equal("          ", @format_o.expand("\t  "))\r
1408       assert_nothing_raised { @format_o.tabstop = 4 }\r
1409       assert_equal("      ", @format_o.expand("\t  "))\r
1410     end\r
1412     def test_unexpand\r
1413       assert_nothing_raised { @format_o = Text::Format.new }\r
1414       assert_equal("\t  ", @format_o.unexpand("          "))\r
1415       assert_nothing_raised { @format_o.tabstop = 4 }\r
1416       assert_equal("\t  ", @format_o.unexpand("      "))\r
1417     end\r
1419     def test_space_only\r
1420       assert_equal("", Text::Format.new.format(" "))\r
1421       assert_equal("", Text::Format.new.format("\n"))\r
1422       assert_equal("", Text::Format.new.format("        "))\r
1423       assert_equal("", Text::Format.new.format("    \n"))\r
1424       assert_equal("", Text::Format.new.paragraphs("\n"))\r
1425       assert_equal("", Text::Format.new.paragraphs(" "))\r
1426       assert_equal("", Text::Format.new.paragraphs("        "))\r
1427       assert_equal("", Text::Format.new.paragraphs("    \n"))\r
1428       assert_equal("", Text::Format.new.paragraphs(["\n"]))\r
1429       assert_equal("", Text::Format.new.paragraphs([" "]))\r
1430       assert_equal("", Text::Format.new.paragraphs(["        "]))\r
1431       assert_equal("", Text::Format.new.paragraphs(["    \n"]))\r
1432     end\r
1434     def test_splendiferous\r
1435       h = nil\r
1436       test = "This is a splendiferous test"\r
1437       assert_nothing_raised { @format_o = Text::Format.new(:columns => 6, :left_margin => 0, :indent => 0, :first_indent => 0) }\r
1438       assert_match(/^splendiferous$/, @format_o.format(test))\r
1439       assert_nothing_raised { @format_o.hard_margins = true }\r
1440       assert_match(/^lendif$/, @format_o.format(test))\r
1441       assert_nothing_raised { h = Object.new }\r
1442       assert_nothing_raised do\r
1443         @format_o.split_rules = Text::Format::SPLIT_HYPHENATION\r
1444         class << h #:nodoc:\r
1445           def hyphenate_to(word, size)\r
1446             return ["", word] if size < 2\r
1447             [word[0 ... size], word[size .. -1]]\r
1448           end\r
1449         end\r
1450         @format_o.hyphenator = h\r
1451       end\r
1452       assert_match(/^iferou$/, @format_o.format(test))\r
1453       assert_nothing_raised { h = Object.new }\r
1454       assert_nothing_raised do\r
1455         class << h #:nodoc:\r
1456           def hyphenate_to(word, size, formatter)\r
1457             return ["", word] if word.size < formatter.columns\r
1458             [word[0 ... size], word[size .. -1]]\r
1459           end\r
1460         end\r
1461         @format_o.hyphenator = h\r
1462       end\r
1463       assert_match(/^ferous$/, @format_o.format(test))\r
1464     end\r
1465   end\r
1466 end\r