From f72dd368b305d352a6658fafe6a4a993bba97b32 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Fri, 1 Jan 2010 14:44:11 +1100 Subject: Silence @text not initialized warning --- .../vendor/text-format-0.6.3/text/format.rb | 2933 ++++++++++---------- 1 file changed, 1467 insertions(+), 1466 deletions(-) diff --git a/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb b/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb index 2d20c7a6a1..3a0e04bd77 100755 --- a/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +++ b/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb @@ -1,1466 +1,1467 @@ -#-- -# Text::Format for Ruby -# Version 0.63 -# -# Copyright (c) 2002 - 2003 Austin Ziegler -# -# $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $ -# -# ========================================================================== -# Revision History :: -# YYYY.MM.DD Change ID Developer -# Description -# -------------------------------------------------------------------------- -# 2002.10.18 Austin Ziegler -# Fixed a minor problem with tabs not being counted. Changed -# abbreviations from Hash to Array to better suit Ruby's -# capabilities. Fixed problems with the way that Array arguments -# are handled in calls to the major object types, excepting in -# Text::Format#expand and Text::Format#unexpand (these will -# probably need to be fixed). -# 2002.10.30 Austin Ziegler -# Fixed the ordering of the <=> for binary tests. Fixed -# Text::Format#expand and Text::Format#unexpand to handle array -# arguments better. -# 2003.01.24 Austin Ziegler -# Fixed a problem with Text::Format::RIGHT_FILL handling where a -# single word is larger than #columns. Removed Comparable -# capabilities (<=> doesn't make sense; == does). Added Symbol -# equivalents for the Hash initialization. Hash initialization has -# been modified so that values are set as follows (Symbols are -# highest priority; strings are middle; defaults are lowest): -# @columns = arg[:columns] || arg['columns'] || @columns -# Added #hard_margins, #split_rules, #hyphenator, and #split_words. -# 2003.02.07 Austin Ziegler -# Fixed the installer for proper case-sensitive handling. -# 2003.03.28 Austin Ziegler -# Added the ability for a hyphenator to receive the formatter -# object. Fixed a bug for strings matching /\A\s*\Z/ failing -# entirely. Fixed a test case failing under 1.6.8. -# 2003.04.04 Austin Ziegler -# Handle the case of hyphenators returning nil for first/rest. -# 2003.09.17 Austin Ziegler -# Fixed a problem where #paragraphs(" ") was raising -# NoMethodError. -# -# ========================================================================== -#++ - -module Text #:nodoc: - # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It - # is available under Ruby's licence, the Perl Artistic licence, or the - # GNU GPL version 2 (or at your option, any later version). As a - # special exception, for use with official Rails (provided by the - # rubyonrails.org development team) and any project created with - # official Rails, the following alternative MIT-style licence may be - # used: - # - # == Text::Format Licence for Rails and Rails Applications - # Permission is hereby granted, free of charge, to any person - # obtaining a copy of this software and associated documentation files - # (the "Software"), to deal in the Software without restriction, - # including without limitation the rights to use, copy, modify, merge, - # publish, distribute, sublicense, and/or sell copies of the Software, - # and to permit persons to whom the Software is furnished to do so, - # subject to the following conditions: - # - # * The names of its contributors may not be used to endorse or - # promote products derived from this software without specific prior - # written permission. - # - # The above copyright notice and this permission notice shall be - # included in all copies or substantial portions of the Software. - # - # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - # SOFTWARE. - class Format - VERSION = '0.63' - - # Local abbreviations. More can be added with Text::Format.abbreviations - ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ] - - # Formatting values - LEFT_ALIGN = 0 - RIGHT_ALIGN = 1 - RIGHT_FILL = 2 - JUSTIFY = 3 - - # Word split modes (only applies when #hard_margins is true). - SPLIT_FIXED = 1 - SPLIT_CONTINUATION = 2 - SPLIT_HYPHENATION = 4 - SPLIT_CONTINUATION_FIXED = SPLIT_CONTINUATION | SPLIT_FIXED - SPLIT_HYPHENATION_FIXED = SPLIT_HYPHENATION | SPLIT_FIXED - SPLIT_HYPHENATION_CONTINUATION = SPLIT_HYPHENATION | SPLIT_CONTINUATION - SPLIT_ALL = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED - - # Words forcibly split by Text::Format will be stored as split words. - # This class represents a word forcibly split. - class SplitWord - # The word that was split. - attr_reader :word - # The first part of the word that was split. - attr_reader :first - # The remainder of the word that was split. - attr_reader :rest - - def initialize(word, first, rest) #:nodoc: - @word = word - @first = first - @rest = rest - end - end - - private - LEQ_RE = /[.?!]['"]?$/ - - def brk_re(i) #:nodoc: - %r/((?:\S+\s+){#{i}})(.+)/ - end - - def posint(p) #:nodoc: - p.to_i.abs - end - - public - # Compares two Text::Format objects. All settings of the objects are - # compared *except* #hyphenator. Generated results (e.g., #split_words) - # are not compared, either. - def ==(o) - (@text == o.text) && - (@columns == o.columns) && - (@left_margin == o.left_margin) && - (@right_margin == o.right_margin) && - (@hard_margins == o.hard_margins) && - (@split_rules == o.split_rules) && - (@first_indent == o.first_indent) && - (@body_indent == o.body_indent) && - (@tag_text == o.tag_text) && - (@tabstop == o.tabstop) && - (@format_style == o.format_style) && - (@extra_space == o.extra_space) && - (@tag_paragraph == o.tag_paragraph) && - (@nobreak == o.nobreak) && - (@abbreviations == o.abbreviations) && - (@nobreak_regex == o.nobreak_regex) - end - - # The text to be manipulated. Note that value is optional, but if the - # formatting functions are called without values, this text is what will - # be formatted. - # - # *Default*:: [] - # Used in:: All methods - attr_accessor :text - - # The total width of the format area. The margins, indentation, and text - # are formatted into this space. - # - # COLUMNS - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here right margin - # - # *Default*:: 72 - # Used in:: #format, #paragraphs, - # #center - attr_reader :columns - - # The total width of the format area. The margins, indentation, and text - # are formatted into this space. The value provided is silently - # converted to a positive integer. - # - # COLUMNS - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here right margin - # - # *Default*:: 72 - # Used in:: #format, #paragraphs, - # #center - def columns=(c) - @columns = posint(c) - end - - # The number of spaces used for the left margin. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # LEFT MARGIN indent text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - attr_reader :left_margin - - # The number of spaces used for the left margin. The value provided is - # silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # LEFT MARGIN indent text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - def left_margin=(left) - @left_margin = posint(left) - end - - # The number of spaces used for the right margin. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here RIGHT MARGIN - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - attr_reader :right_margin - - # The number of spaces used for the right margin. The value provided is - # silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here RIGHT MARGIN - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - def right_margin=(r) - @right_margin = posint(r) - end - - # The number of spaces to indent the first line of a paragraph. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 4 - # Used in:: #format, #paragraphs - attr_reader :first_indent - - # The number of spaces to indent the first line of a paragraph. The - # value provided is silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 4 - # Used in:: #format, #paragraphs - def first_indent=(f) - @first_indent = posint(f) - end - - # The number of spaces to indent all lines after the first line of a - # paragraph. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs - attr_reader :body_indent - - # The number of spaces to indent all lines after the first line of - # a paragraph. The value provided is silently converted to a - # positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs - def body_indent=(b) - @body_indent = posint(b) - end - - # Normally, words larger than the format area will be placed on a line - # by themselves. Setting this to +true+ will force words larger than the - # format area to be split into one or more "words" each at most the size - # of the format area. The first line and the original word will be - # placed into #split_words. Note that this will cause the - # output to look *similar* to a #format_style of JUSTIFY. (Lines will be - # filled as much as possible.) - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :hard_margins - - # An array of words split during formatting if #hard_margins is set to - # +true+. - # #split_words << Text::Format::SplitWord.new(word, first, rest) - attr_reader :split_words - - # The object responsible for hyphenating. It must respond to - # #hyphenate_to(word, size) or #hyphenate_to(word, size, formatter) and - # return an array of the word split into two parts; if there is a - # hyphenation mark to be applied, responsibility belongs to the - # hyphenator object. The size is the MAXIMUM size permitted, including - # any hyphenation marks. If the #hyphenate_to method has an arity of 3, - # the formatter will be provided to the method. This allows the - # hyphenator to make decisions about the hyphenation based on the - # formatting rules. - # - # *Default*:: +nil+ - # Used in:: #format, #paragraphs - attr_reader :hyphenator - - # The object responsible for hyphenating. It must respond to - # #hyphenate_to(word, size) and return an array of the word hyphenated - # into two parts. The size is the MAXIMUM size permitted, including any - # hyphenation marks. - # - # *Default*:: +nil+ - # Used in:: #format, #paragraphs - def hyphenator=(h) - raise ArgumentError, "#{h.inspect} is not a valid hyphenator." unless h.respond_to?(:hyphenate_to) - arity = h.method(:hyphenate_to).arity - raise ArgumentError, "#{h.inspect} must have exactly two or three arguments." unless [2, 3].include?(arity) - @hyphenator = h - @hyphenator_arity = arity - end - - # Specifies the split mode; used only when #hard_margins is set to - # +true+. Allowable values are: - # [+SPLIT_FIXED+] The word will be split at the number of - # characters needed, with no marking at all. - # repre - # senta - # ion - # [+SPLIT_CONTINUATION+] The word will be split at the number of - # characters needed, with a C-style continuation - # character. If a word is the only item on a - # line and it cannot be split into an - # appropriate size, SPLIT_FIXED will be used. - # repr\ - # esen\ - # tati\ - # on - # [+SPLIT_HYPHENATION+] The word will be split according to the - # hyphenator specified in #hyphenator. If there - # is no #hyphenator specified, works like - # SPLIT_CONTINUATION. The example is using - # TeX::Hyphen. If a word is the only item on a - # line and it cannot be split into an - # appropriate size, SPLIT_CONTINUATION mode will - # be used. - # rep- - # re- - # sen- - # ta- - # tion - # - # *Default*:: Text::Format::SPLIT_FIXED - # Used in:: #format, #paragraphs - attr_reader :split_rules - - # Specifies the split mode; used only when #hard_margins is set to - # +true+. Allowable values are: - # [+SPLIT_FIXED+] The word will be split at the number of - # characters needed, with no marking at all. - # repre - # senta - # ion - # [+SPLIT_CONTINUATION+] The word will be split at the number of - # characters needed, with a C-style continuation - # character. - # repr\ - # esen\ - # tati\ - # on - # [+SPLIT_HYPHENATION+] The word will be split according to the - # hyphenator specified in #hyphenator. If there - # is no #hyphenator specified, works like - # SPLIT_CONTINUATION. The example is using - # TeX::Hyphen as the #hyphenator. - # rep- - # re- - # sen- - # ta- - # tion - # - # These values can be bitwise ORed together (e.g., SPLIT_FIXED | - # SPLIT_CONTINUATION) to provide fallback split methods. In the - # example given, an attempt will be made to split the word using the - # rules of SPLIT_CONTINUATION; if there is not enough room, the word - # will be split with the rules of SPLIT_FIXED. These combinations are - # also available as the following values: - # * +SPLIT_CONTINUATION_FIXED+ - # * +SPLIT_HYPHENATION_FIXED+ - # * +SPLIT_HYPHENATION_CONTINUATION+ - # * +SPLIT_ALL+ - # - # *Default*:: Text::Format::SPLIT_FIXED - # Used in:: #format, #paragraphs - def split_rules=(s) - raise ArgumentError, "Invalid value provided for split_rules." if ((s < SPLIT_FIXED) || (s > SPLIT_ALL)) - @split_rules = s - end - - # Indicates whether sentence terminators should be followed by a single - # space (+false+), or two spaces (+true+). - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :extra_space - - # Defines the current abbreviations as an array. This is only used if - # extra_space is turned on. - # - # If one is abbreviating "President" as "Pres." (abbreviations = - # ["Pres"]), then the results of formatting will be as illustrated in - # the table below: - # - # extra_space | include? | !include? - # true | Pres. Lincoln | Pres. Lincoln - # false | Pres. Lincoln | Pres. Lincoln - # - # *Default*:: {} - # Used in:: #format, #paragraphs - attr_accessor :abbreviations - - # Indicates whether the formatting of paragraphs should be done with - # tagged paragraphs. Useful only with #tag_text. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :tag_paragraph - - # The array of text to be placed before each paragraph when - # #tag_paragraph is +true+. When #format() is called, - # only the first element of the array is used. When #paragraphs - # is called, then each entry in the array will be used once, with - # corresponding paragraphs. If the tag elements are exhausted before the - # text is exhausted, then the remaining paragraphs will not be tagged. - # Regardless of indentation settings, a blank line will be inserted - # between all paragraphs when #tag_paragraph is +true+. - # - # *Default*:: [] - # Used in:: #format, #paragraphs - attr_accessor :tag_text - - # Indicates whether or not the non-breaking space feature should be - # used. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :nobreak - - # A hash which holds the regular expressions on which spaces should not - # be broken. The hash is set up such that the key is the first word and - # the value is the second word. - # - # For example, if +nobreak_regex+ contains the following hash: - # - # { '^Mrs?\.$' => '\S+$', '^\S+$' => '^(?:S|J)r\.$'} - # - # Then "Mr. Jones", "Mrs. Jones", and "Jones Jr." would not be broken. - # If this simple matching algorithm indicates that there should not be a - # break at the current end of line, then a backtrack is done until there - # are two words on which line breaking is permitted. If two such words - # are not found, then the end of the line will be broken *regardless*. - # If there is a single word on the current line, then no backtrack is - # done and the word is stuck on the end. - # - # *Default*:: {} - # Used in:: #format, #paragraphs - attr_accessor :nobreak_regex - - # Indicates the number of spaces that a single tab represents. - # - # *Default*:: 8 - # Used in:: #expand, #unexpand, - # #paragraphs - attr_reader :tabstop - - # Indicates the number of spaces that a single tab represents. - # - # *Default*:: 8 - # Used in:: #expand, #unexpand, - # #paragraphs - def tabstop=(t) - @tabstop = posint(t) - end - - # Specifies the format style. Allowable values are: - # [+LEFT_ALIGN+] Left justified, ragged right. - # |A paragraph that is| - # |left aligned.| - # [+RIGHT_ALIGN+] Right justified, ragged left. - # |A paragraph that is| - # | right aligned.| - # [+RIGHT_FILL+] Left justified, right ragged, filled to width by - # spaces. (Essentially the same as +LEFT_ALIGN+ except - # that lines are padded on the right.) - # |A paragraph that is| - # |left aligned. | - # [+JUSTIFY+] Fully justified, words filled to width by spaces, - # except the last line. - # |A paragraph that| - # |is justified.| - # - # *Default*:: Text::Format::LEFT_ALIGN - # Used in:: #format, #paragraphs - attr_reader :format_style - - # Specifies the format style. Allowable values are: - # [+LEFT_ALIGN+] Left justified, ragged right. - # |A paragraph that is| - # |left aligned.| - # [+RIGHT_ALIGN+] Right justified, ragged left. - # |A paragraph that is| - # | right aligned.| - # [+RIGHT_FILL+] Left justified, right ragged, filled to width by - # spaces. (Essentially the same as +LEFT_ALIGN+ except - # that lines are padded on the right.) - # |A paragraph that is| - # |left aligned. | - # [+JUSTIFY+] Fully justified, words filled to width by spaces. - # |A paragraph that| - # |is justified.| - # - # *Default*:: Text::Format::LEFT_ALIGN - # Used in:: #format, #paragraphs - def format_style=(fs) - raise ArgumentError, "Invalid value provided for format_style." if ((fs < LEFT_ALIGN) || (fs > JUSTIFY)) - @format_style = fs - end - - # Indicates that the format style is left alignment. - # - # *Default*:: +true+ - # Used in:: #format, #paragraphs - def left_align? - return @format_style == LEFT_ALIGN - end - - # Indicates that the format style is right alignment. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def right_align? - return @format_style == RIGHT_ALIGN - end - - # Indicates that the format style is right fill. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def right_fill? - return @format_style == RIGHT_FILL - end - - # Indicates that the format style is full justification. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def justify? - return @format_style == JUSTIFY - end - - # The default implementation of #hyphenate_to implements - # SPLIT_CONTINUATION. - def hyphenate_to(word, size) - [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]] - end - - private - def __do_split_word(word, size) #:nodoc: - [word[0 .. (size - 1)], word[size .. -1]] - end - - def __format(to_wrap) #:nodoc: - words = to_wrap.split(/\s+/).compact - words.shift if words[0].nil? or words[0].empty? - to_wrap = [] - - abbrev = false - width = @columns - @first_indent - @left_margin - @right_margin - indent_str = ' ' * @first_indent - first_line = true - line = words.shift - abbrev = __is_abbrev(line) unless line.nil? || line.empty? - - while w = words.shift - if (w.size + line.size < (width - 1)) || - ((line !~ LEQ_RE || abbrev) && (w.size + line.size < width)) - line << " " if (line =~ LEQ_RE) && (not abbrev) - line << " #{w}" - else - line, w = __do_break(line, w) if @nobreak - line, w = __do_hyphenate(line, w, width) if @hard_margins - if w.index(/\s+/) - w, *w2 = w.split(/\s+/) - words.unshift(w2) - words.flatten! - end - to_wrap << __make_line(line, indent_str, width, w.nil?) unless line.nil? - if first_line - first_line = false - width = @columns - @body_indent - @left_margin - @right_margin - indent_str = ' ' * @body_indent - end - line = w - end - - abbrev = __is_abbrev(w) unless w.nil? - end - - loop do - break if line.nil? or line.empty? - line, w = __do_hyphenate(line, w, width) if @hard_margins - to_wrap << __make_line(line, indent_str, width, w.nil?) - line = w - end - - if (@tag_paragraph && (to_wrap.size > 0)) then - clr = %r{`(\w+)'}.match([caller(1)].flatten[0])[1] - clr = "" if clr.nil? - - if ((not @tag_text[0].nil?) && (@tag_cur.size < 1) && - (clr != "__paragraphs")) then - @tag_cur = @tag_text[0] - end - - fchar = /(\S)/.match(to_wrap[0])[1] - white = to_wrap[0].index(fchar) - if ((white - @left_margin - 1) > @tag_cur.size) then - white = @tag_cur.size + @left_margin - to_wrap[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}") - else - to_wrap.unshift("#{' ' * @left_margin}#{@tag_cur}\n") - end - end - to_wrap.join('') - end - - # format lines in text into paragraphs with each element of @wrap a - # paragraph; uses Text::Format.format for the formatting - def __paragraphs(to_wrap) #:nodoc: - if ((@first_indent == @body_indent) || @tag_paragraph) then - p_end = "\n" - else - p_end = '' - end - - cnt = 0 - ret = [] - to_wrap.each do |tw| - @tag_cur = @tag_text[cnt] if @tag_paragraph - @tag_cur = '' if @tag_cur.nil? - line = __format(tw) - ret << "#{line}#{p_end}" if (not line.nil?) && (line.size > 0) - cnt += 1 - end - - ret[-1].chomp! unless ret.empty? - ret.join('') - end - - # center text using spaces on left side to pad it out empty lines - # are preserved - def __center(to_center) #:nodoc: - tabs = 0 - width = @columns - @left_margin - @right_margin - centered = [] - to_center.each do |tc| - s = tc.strip - tabs = s.count("\t") - tabs = 0 if tabs.nil? - ct = ((width - s.size - (tabs * @tabstop) + tabs) / 2) - ct = (width - @left_margin - @right_margin) - ct - centered << "#{s.rjust(ct)}\n" - end - centered.join('') - end - - # expand tabs to spaces should be similar to Text::Tabs::expand - def __expand(to_expand) #:nodoc: - expanded = [] - to_expand.split("\n").each { |te| expanded << te.gsub(/\t/, ' ' * @tabstop) } - expanded.join('') - end - - def __unexpand(to_unexpand) #:nodoc: - unexpanded = [] - to_unexpand.split("\n").each { |tu| unexpanded << tu.gsub(/ {#{@tabstop}}/, "\t") } - unexpanded.join('') - end - - def __is_abbrev(word) #:nodoc: - # remove period if there is one. - w = word.gsub(/\.$/, '') unless word.nil? - return true if (!@extra_space || ABBREV.include?(w) || @abbreviations.include?(w)) - false - end - - def __make_line(line, indent, width, last = false) #:nodoc: - lmargin = " " * @left_margin - fill = " " * (width - line.size) if right_fill? && (line.size <= width) - - if (justify? && ((not line.nil?) && (not line.empty?)) && line =~ /\S+\s+\S+/ && !last) - spaces = width - line.size - words = line.split(/(\s+)/) - ws = spaces / (words.size / 2) - spaces = spaces % (words.size / 2) if ws > 0 - words.reverse.each do |rw| - next if (rw =~ /^\S/) - rw.sub!(/^/, " " * ws) - next unless (spaces > 0) - rw.sub!(/^/, " ") - spaces -= 1 - end - line = words.join('') - end - line = "#{lmargin}#{indent}#{line}#{fill}\n" unless line.nil? - if right_align? && (not line.nil?) - line.sub(/^/, " " * (@columns - @right_margin - (line.size - 1))) - else - line - end - end - - def __do_hyphenate(line, next_line, width) #:nodoc: - rline = line.dup rescue line - rnext = next_line.dup rescue next_line - loop do - if rline.size == width - break - elsif rline.size > width - words = rline.strip.split(/\s+/) - word = words[-1].dup - size = width - rline.size + word.size - if (size <= 0) - words[-1] = nil - rline = words.join(' ').strip - rnext = "#{word} #{rnext}".strip - next - end - - first = rest = nil - - if ((@split_rules & SPLIT_HYPHENATION) != 0) - if @hyphenator_arity == 2 - first, rest = @hyphenator.hyphenate_to(word, size) - else - first, rest = @hyphenator.hyphenate_to(word, size, self) - end - end - - if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? - first, rest = self.hyphenate_to(word, size) - end - - if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? - first.nil? or @split_rules == SPLIT_FIXED - first, rest = __do_split_word(word, size) - end - - if first.nil? - words[-1] = nil - rest = word - else - words[-1] = first - @split_words << SplitWord.new(word, first, rest) - end - rline = words.join(' ').strip - rnext = "#{rest} #{rnext}".strip - break - else - break if rnext.nil? or rnext.empty? or rline.nil? or rline.empty? - words = rnext.split(/\s+/) - word = words.shift - size = width - rline.size - 1 - - if (size <= 0) - rnext = "#{word} #{words.join(' ')}".strip - break - end - - first = rest = nil - - if ((@split_rules & SPLIT_HYPHENATION) != 0) - if @hyphenator_arity == 2 - first, rest = @hyphenator.hyphenate_to(word, size) - else - first, rest = @hyphenator.hyphenate_to(word, size, self) - end - end - - first, rest = self.hyphenate_to(word, size) if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? - - first, rest = __do_split_word(word, size) if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? - - if (rline.size + (first ? first.size : 0)) < width - @split_words << SplitWord.new(word, first, rest) - rline = "#{rline} #{first}".strip - rnext = "#{rest} #{words.join(' ')}".strip - end - break - end - end - [rline, rnext] - end - - def __do_break(line, next_line) #:nodoc: - no_brk = false - words = [] - words = line.split(/\s+/) unless line.nil? - last_word = words[-1] - - @nobreak_regex.each { |k, v| no_brk = ((last_word =~ /#{k}/) and (next_line =~ /#{v}/)) } - - if no_brk && words.size > 1 - i = words.size - while i > 0 - no_brk = false - @nobreak_regex.each { |k, v| no_brk = ((words[i + 1] =~ /#{k}/) && (words[i] =~ /#{v}/)) } - i -= 1 - break if not no_brk - end - if i > 0 - l = brk_re(i).match(line) - line.sub!(brk_re(i), l[1]) - next_line = "#{l[2]} #{next_line}" - line.sub!(/\s+$/, '') - end - end - [line, next_line] - end - - def __create(arg = nil, &block) #:nodoc: - # Format::Text.new(text-to-wrap) - @text = arg unless arg.nil? - # Defaults - @columns = 72 - @tabstop = 8 - @first_indent = 4 - @body_indent = 0 - @format_style = LEFT_ALIGN - @left_margin = 0 - @right_margin = 0 - @extra_space = false - @text = Array.new if @text.nil? - @tag_paragraph = false - @tag_text = Array.new - @tag_cur = "" - @abbreviations = Array.new - @nobreak = false - @nobreak_regex = Hash.new - @split_words = Array.new - @hard_margins = false - @split_rules = SPLIT_FIXED - @hyphenator = self - @hyphenator_arity = self.method(:hyphenate_to).arity - - instance_eval(&block) unless block.nil? - end - - public - # Formats text into a nice paragraph format. The text is separated - # into words and then reassembled a word at a time using the settings - # of this Format object. If a word is larger than the number of - # columns available for formatting, then that word will appear on the - # line by itself. - # - # If +to_wrap+ is +nil+, then the value of #text will be - # worked on. - def format(to_wrap = nil) - to_wrap = @text if to_wrap.nil? - if to_wrap.class == Array - __format(to_wrap[0]) - else - __format(to_wrap) - end - end - - # Considers each element of text (provided or internal) as a paragraph. - # If #first_indent is the same as #body_indent, then - # paragraphs will be separated by a single empty line in the result; - # otherwise, the paragraphs will follow immediately after each other. - # Uses #format to do the heavy lifting. - def paragraphs(to_wrap = nil) - to_wrap = @text if to_wrap.nil? - __paragraphs([to_wrap].flatten) - end - - # Centers the text, preserving empty lines and tabs. - def center(to_center = nil) - to_center = @text if to_center.nil? - __center([to_center].flatten) - end - - # Replaces all tab characters in the text with #tabstop spaces. - def expand(to_expand = nil) - to_expand = @text if to_expand.nil? - if to_expand.class == Array - to_expand.collect { |te| __expand(te) } - else - __expand(to_expand) - end - end - - # Replaces all occurrences of #tabstop consecutive spaces - # with a tab character. - def unexpand(to_unexpand = nil) - to_unexpand = @text if to_unexpand.nil? - if to_unexpand.class == Array - to_unexpand.collect { |te| v << __unexpand(te) } - else - __unexpand(to_unexpand) - end - end - - # This constructor takes advantage of a technique for Ruby object - # construction introduced by Andy Hunt and Dave Thomas (see reference), - # where optional values are set using commands in a block. - # - # Text::Format.new { - # columns = 72 - # left_margin = 0 - # right_margin = 0 - # first_indent = 4 - # body_indent = 0 - # format_style = Text::Format::LEFT_ALIGN - # extra_space = false - # abbreviations = {} - # tag_paragraph = false - # tag_text = [] - # nobreak = false - # nobreak_regex = {} - # tabstop = 8 - # text = nil - # } - # - # As shown above, +arg+ is optional. If +arg+ is specified and is a - # +String+, then arg is used as the default value of #text. - # Alternately, an existing Text::Format object can be used or a Hash can - # be used. With all forms, a block can be specified. - # - # *Reference*:: "Object Construction and Blocks" - # - # - def initialize(arg = nil, &block) - case arg - when Text::Format - __create(arg.text) do - @columns = arg.columns - @tabstop = arg.tabstop - @first_indent = arg.first_indent - @body_indent = arg.body_indent - @format_style = arg.format_style - @left_margin = arg.left_margin - @right_margin = arg.right_margin - @extra_space = arg.extra_space - @tag_paragraph = arg.tag_paragraph - @tag_text = arg.tag_text - @abbreviations = arg.abbreviations - @nobreak = arg.nobreak - @nobreak_regex = arg.nobreak_regex - @text = arg.text - @hard_margins = arg.hard_margins - @split_words = arg.split_words - @split_rules = arg.split_rules - @hyphenator = arg.hyphenator - end - instance_eval(&block) unless block.nil? - when Hash - __create do - @columns = arg[:columns] || arg['columns'] || @columns - @tabstop = arg[:tabstop] || arg['tabstop'] || @tabstop - @first_indent = arg[:first_indent] || arg['first_indent'] || @first_indent - @body_indent = arg[:body_indent] || arg['body_indent'] || @body_indent - @format_style = arg[:format_style] || arg['format_style'] || @format_style - @left_margin = arg[:left_margin] || arg['left_margin'] || @left_margin - @right_margin = arg[:right_margin] || arg['right_margin'] || @right_margin - @extra_space = arg[:extra_space] || arg['extra_space'] || @extra_space - @text = arg[:text] || arg['text'] || @text - @tag_paragraph = arg[:tag_paragraph] || arg['tag_paragraph'] || @tag_paragraph - @tag_text = arg[:tag_text] || arg['tag_text'] || @tag_text - @abbreviations = arg[:abbreviations] || arg['abbreviations'] || @abbreviations - @nobreak = arg[:nobreak] || arg['nobreak'] || @nobreak - @nobreak_regex = arg[:nobreak_regex] || arg['nobreak_regex'] || @nobreak_regex - @hard_margins = arg[:hard_margins] || arg['hard_margins'] || @hard_margins - @split_rules = arg[:split_rules] || arg['split_rules'] || @split_rules - @hyphenator = arg[:hyphenator] || arg['hyphenator'] || @hyphenator - end - instance_eval(&block) unless block.nil? - when String - __create(arg, &block) - when NilClass - __create(&block) - else - raise TypeError - end - end - end -end - -if __FILE__ == $0 - require 'test/unit' - - class TestText__Format < Test::Unit::TestCase #:nodoc: - attr_accessor :format_o - - GETTYSBURG = <<-'EOS' - Four score and seven years ago our fathers brought forth on this - continent a new nation, conceived in liberty and dedicated to the - proposition that all men are created equal. Now we are engaged in - a great civil war, testing whether that nation or any nation so - conceived and so dedicated can long endure. We are met on a great - battlefield of that war. We have come to dedicate a portion of - that field as a final resting-place for those who here gave their - lives that that nation might live. It is altogether fitting and - proper that we should do this. But in a larger sense, we cannot - dedicate, we cannot consecrate, we cannot hallow this ground. - The brave men, living and dead who struggled here have consecrated - it far above our poor power to add or detract. The world will - little note nor long remember what we say here, but it can never - forget what they did here. It is for us the living rather to be - dedicated here to the unfinished work which they who fought here - have thus far so nobly advanced. It is rather for us to be here - dedicated to the great task remaining before us--that from these - honored dead we take increased devotion to that cause for which - they gave the last full measure of devotion--that we here highly - resolve that these dead shall not have died in vain, that this - nation under God shall have a new birth of freedom, and that - government of the people, by the people, for the people shall - not perish from the earth. - - -- Pres. Abraham Lincoln, 19 November 1863 - EOS - - 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" - - 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" - - # Tests both abbreviations and abbreviations= - def test_abbreviations - abbr = [" Pres. Abraham Lincoln\n", " Pres. Abraham Lincoln\n"] - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.abbreviations) - assert_nothing_raised { @format_o.abbreviations = [ 'foo', 'bar' ] } - assert_equal([ 'foo', 'bar' ], @format_o.abbreviations) - assert_equal(abbr[0], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.extra_space = true } - assert_equal(abbr[1], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.abbreviations = [ "Pres" ] } - assert_equal([ "Pres" ], @format_o.abbreviations) - assert_equal(abbr[0], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.extra_space = false } - assert_equal(abbr[0], @format_o.format(abbr[0])) - end - - # Tests both body_indent and body_indent= - def test_body_indent - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = 7 } - assert_equal(7, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = -3 } - assert_equal(3, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = "9" } - assert_equal(9, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = "-2" } - assert_equal(2, @format_o.body_indent) - assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[1]) - end - - # Tests both columns and columns= - def test_columns - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(72, @format_o.columns) - assert_nothing_raised { @format_o.columns = 7 } - assert_equal(7, @format_o.columns) - assert_nothing_raised { @format_o.columns = -3 } - assert_equal(3, @format_o.columns) - assert_nothing_raised { @format_o.columns = "9" } - assert_equal(9, @format_o.columns) - assert_nothing_raised { @format_o.columns = "-2" } - assert_equal(2, @format_o.columns) - assert_nothing_raised { @format_o.columns = 40 } - assert_equal(40, @format_o.columns) - assert_match(/this continent$/, - @format_o.format(GETTYSBURG).split("\n")[1]) - end - - # Tests both extra_space and extra_space= - def test_extra_space - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.extra_space) - assert_nothing_raised { @format_o.extra_space = true } - assert(@format_o.extra_space) - # The behaviour of extra_space is tested in test_abbreviations. There - # is no need to reproduce it here. - end - - # Tests both first_indent and first_indent= - def test_first_indent - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(4, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = 7 } - assert_equal(7, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = -3 } - assert_equal(3, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = "9" } - assert_equal(9, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = "-2" } - assert_equal(2, @format_o.first_indent) - assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[0]) - end - - def test_format_style - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(Text::Format::LEFT_ALIGN, @format_o.format_style) - assert_match(/^November 1863$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert_equal(Text::Format::RIGHT_ALIGN, @format_o.format_style) - assert_match(/^ +November 1863$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert_equal(Text::Format::RIGHT_FILL, @format_o.format_style) - assert_match(/^November 1863 +$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert_equal(Text::Format::JUSTIFY, @format_o.format_style) - assert_match(/^of freedom, and that government of the people, by the people, for the$/, - @format_o.format(GETTYSBURG).split("\n")[-3]) - assert_raise(ArgumentError) { @format_o.format_style = 33 } - end - - def test_tag_paragraph - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.tag_paragraph) - assert_nothing_raised { @format_o.tag_paragraph = true } - assert(@format_o.tag_paragraph) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) - end - - def test_tag_text - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.tag_text) - assert_equal(@format_o.format(GETTYSBURG), - Text::Format.new.format(GETTYSBURG)) - assert_nothing_raised { - @format_o.tag_paragraph = true - @format_o.tag_text = ["Gettysburg Address", "---"] - } - assert_not_equal(@format_o.format(GETTYSBURG), - Text::Format.new.format(GETTYSBURG)) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG, - GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG, - GETTYSBURG])) - end - - def test_justify? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::JUSTIFY - } - assert(@format_o.justify?) - # The format testing is done in test_format_style - end - - def test_left_align? - assert_nothing_raised { @format_o = Text::Format.new } - assert(@format_o.left_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.left_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.left_align?) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert(!@format_o.left_align?) - # The format testing is done in test_format_style - end - - def test_left_margin - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = -3 } - assert_equal(3, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = "9" } - assert_equal(9, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = "-2" } - assert_equal(2, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = 7 } - assert_equal(7, @format_o.left_margin) - assert_nothing_raised { - ft = @format_o.format(GETTYSBURG).split("\n") - assert_match(/^ {11}Four score/, ft[0]) - assert_match(/^ {7}November/, ft[-1]) - } - end - - def test_hard_margins - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.hard_margins) - assert_nothing_raised { - @format_o.hard_margins = true - @format_o.columns = 5 - @format_o.first_indent = 0 - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(@format_o.hard_margins) - assert_equal(FIVE_COL, @format_o.format(GETTYSBURG)) - assert_nothing_raised { - @format_o.split_rules |= Text::Format::SPLIT_CONTINUATION - assert_equal(Text::Format::SPLIT_CONTINUATION_FIXED, - @format_o.split_rules) - } - assert_equal(FIVE_CNT, @format_o.format(GETTYSBURG)) - end - - # Tests both nobreak and nobreak_regex, since one is only useful - # with the other. - def test_nobreak - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.nobreak) - assert(@format_o.nobreak_regex.empty?) - assert_nothing_raised { - @format_o.nobreak = true - @format_o.nobreak_regex = { '^this$' => '^continent$' } - @format_o.columns = 77 - } - assert(@format_o.nobreak) - assert_equal({ '^this$' => '^continent$' }, @format_o.nobreak_regex) - assert_match(/^this continent/, - @format_o.format(GETTYSBURG).split("\n")[1]) - end - - def test_right_align? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.right_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(@format_o.right_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.right_align?) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert(!@format_o.right_align?) - # The format testing is done in test_format_style - end - - def test_right_fill? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::JUSTIFY - } - assert(!@format_o.right_fill?) - # The format testing is done in test_format_style - end - - def test_right_margin - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = -3 } - assert_equal(3, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = "9" } - assert_equal(9, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = "-2" } - assert_equal(2, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = 7 } - assert_equal(7, @format_o.right_margin) - assert_nothing_raised { - ft = @format_o.format(GETTYSBURG).split("\n") - assert_match(/^ {4}Four score.*forth on$/, ft[0]) - assert_match(/^November/, ft[-1]) - } - end - - def test_tabstop - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(8, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = 7 } - assert_equal(7, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = -3 } - assert_equal(3, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = "9" } - assert_equal(9, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = "-2" } - assert_equal(2, @format_o.tabstop) - end - - def test_text - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.text) - assert_nothing_raised { @format_o.text = "Test Text" } - assert_equal("Test Text", @format_o.text) - assert_nothing_raised { @format_o.text = ["Line 1", "Line 2"] } - assert_equal(["Line 1", "Line 2"], @format_o.text) - end - - def test_s_new - # new(NilClass) { block } - assert_nothing_raised do - @format_o = Text::Format.new { - self.text = "Test 1, 2, 3" - } - end - assert_equal("Test 1, 2, 3", @format_o.text) - - # new(Hash Symbols) - assert_nothing_raised { @format_o = Text::Format.new(:columns => 72) } - assert_equal(72, @format_o.columns) - - # new(Hash String) - assert_nothing_raised { @format_o = Text::Format.new('columns' => 72) } - assert_equal(72, @format_o.columns) - - # new(Hash) { block } - assert_nothing_raised do - @format_o = Text::Format.new('columns' => 80) { - self.text = "Test 4, 5, 6" - } - end - assert_equal("Test 4, 5, 6", @format_o.text) - assert_equal(80, @format_o.columns) - - # new(Text::Format) - assert_nothing_raised do - fo = Text::Format.new(@format_o) - assert(fo == @format_o) - end - - # new(Text::Format) { block } - assert_nothing_raised do - fo = Text::Format.new(@format_o) { self.columns = 79 } - assert(fo != @format_o) - end - - # new(String) - assert_nothing_raised { @format_o = Text::Format.new("Test A, B, C") } - assert_equal("Test A, B, C", @format_o.text) - - # new(String) { block } - assert_nothing_raised do - @format_o = Text::Format.new("Test X, Y, Z") { self.columns = -5 } - end - assert_equal("Test X, Y, Z", @format_o.text) - assert_equal(5, @format_o.columns) - end - - def test_center - assert_nothing_raised { @format_o = Text::Format.new } - assert_nothing_raised do - ct = @format_o.center(GETTYSBURG.split("\n")).split("\n") - assert_match(/^ Four score and seven years ago our fathers brought forth on this/, ct[0]) - assert_match(/^ not perish from the earth./, ct[-3]) - end - end - - def test_expand - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(" ", @format_o.expand("\t ")) - assert_nothing_raised { @format_o.tabstop = 4 } - assert_equal(" ", @format_o.expand("\t ")) - end - - def test_unexpand - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal("\t ", @format_o.unexpand(" ")) - assert_nothing_raised { @format_o.tabstop = 4 } - assert_equal("\t ", @format_o.unexpand(" ")) - end - - def test_space_only - assert_equal("", Text::Format.new.format(" ")) - assert_equal("", Text::Format.new.format("\n")) - assert_equal("", Text::Format.new.format(" ")) - assert_equal("", Text::Format.new.format(" \n")) - assert_equal("", Text::Format.new.paragraphs("\n")) - assert_equal("", Text::Format.new.paragraphs(" ")) - assert_equal("", Text::Format.new.paragraphs(" ")) - assert_equal("", Text::Format.new.paragraphs(" \n")) - assert_equal("", Text::Format.new.paragraphs(["\n"])) - assert_equal("", Text::Format.new.paragraphs([" "])) - assert_equal("", Text::Format.new.paragraphs([" "])) - assert_equal("", Text::Format.new.paragraphs([" \n"])) - end - - def test_splendiferous - h = nil - test = "This is a splendiferous test" - assert_nothing_raised { @format_o = Text::Format.new(:columns => 6, :left_margin => 0, :indent => 0, :first_indent => 0) } - assert_match(/^splendiferous$/, @format_o.format(test)) - assert_nothing_raised { @format_o.hard_margins = true } - assert_match(/^lendif$/, @format_o.format(test)) - assert_nothing_raised { h = Object.new } - assert_nothing_raised do - @format_o.split_rules = Text::Format::SPLIT_HYPHENATION - class << h #:nodoc: - def hyphenate_to(word, size) - return ["", word] if size < 2 - [word[0 ... size], word[size .. -1]] - end - end - @format_o.hyphenator = h - end - assert_match(/^iferou$/, @format_o.format(test)) - assert_nothing_raised { h = Object.new } - assert_nothing_raised do - class << h #:nodoc: - def hyphenate_to(word, size, formatter) - return ["", word] if word.size < formatter.columns - [word[0 ... size], word[size .. -1]] - end - end - @format_o.hyphenator = h - end - assert_match(/^ferous$/, @format_o.format(test)) - end - end -end +#-- +# Text::Format for Ruby +# Version 0.63 +# +# Copyright (c) 2002 - 2003 Austin Ziegler +# +# $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $ +# +# ========================================================================== +# Revision History :: +# YYYY.MM.DD Change ID Developer +# Description +# -------------------------------------------------------------------------- +# 2002.10.18 Austin Ziegler +# Fixed a minor problem with tabs not being counted. Changed +# abbreviations from Hash to Array to better suit Ruby's +# capabilities. Fixed problems with the way that Array arguments +# are handled in calls to the major object types, excepting in +# Text::Format#expand and Text::Format#unexpand (these will +# probably need to be fixed). +# 2002.10.30 Austin Ziegler +# Fixed the ordering of the <=> for binary tests. Fixed +# Text::Format#expand and Text::Format#unexpand to handle array +# arguments better. +# 2003.01.24 Austin Ziegler +# Fixed a problem with Text::Format::RIGHT_FILL handling where a +# single word is larger than #columns. Removed Comparable +# capabilities (<=> doesn't make sense; == does). Added Symbol +# equivalents for the Hash initialization. Hash initialization has +# been modified so that values are set as follows (Symbols are +# highest priority; strings are middle; defaults are lowest): +# @columns = arg[:columns] || arg['columns'] || @columns +# Added #hard_margins, #split_rules, #hyphenator, and #split_words. +# 2003.02.07 Austin Ziegler +# Fixed the installer for proper case-sensitive handling. +# 2003.03.28 Austin Ziegler +# Added the ability for a hyphenator to receive the formatter +# object. Fixed a bug for strings matching /\A\s*\Z/ failing +# entirely. Fixed a test case failing under 1.6.8. +# 2003.04.04 Austin Ziegler +# Handle the case of hyphenators returning nil for first/rest. +# 2003.09.17 Austin Ziegler +# Fixed a problem where #paragraphs(" ") was raising +# NoMethodError. +# +# ========================================================================== +#++ + +module Text #:nodoc: + # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It + # is available under Ruby's licence, the Perl Artistic licence, or the + # GNU GPL version 2 (or at your option, any later version). As a + # special exception, for use with official Rails (provided by the + # rubyonrails.org development team) and any project created with + # official Rails, the following alternative MIT-style licence may be + # used: + # + # == Text::Format Licence for Rails and Rails Applications + # Permission is hereby granted, free of charge, to any person + # obtaining a copy of this software and associated documentation files + # (the "Software"), to deal in the Software without restriction, + # including without limitation the rights to use, copy, modify, merge, + # publish, distribute, sublicense, and/or sell copies of the Software, + # and to permit persons to whom the Software is furnished to do so, + # subject to the following conditions: + # + # * The names of its contributors may not be used to endorse or + # promote products derived from this software without specific prior + # written permission. + # + # The above copyright notice and this permission notice shall be + # included in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + # SOFTWARE. + class Format + VERSION = '0.63' + + # Local abbreviations. More can be added with Text::Format.abbreviations + ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ] + + # Formatting values + LEFT_ALIGN = 0 + RIGHT_ALIGN = 1 + RIGHT_FILL = 2 + JUSTIFY = 3 + + # Word split modes (only applies when #hard_margins is true). + SPLIT_FIXED = 1 + SPLIT_CONTINUATION = 2 + SPLIT_HYPHENATION = 4 + SPLIT_CONTINUATION_FIXED = SPLIT_CONTINUATION | SPLIT_FIXED + SPLIT_HYPHENATION_FIXED = SPLIT_HYPHENATION | SPLIT_FIXED + SPLIT_HYPHENATION_CONTINUATION = SPLIT_HYPHENATION | SPLIT_CONTINUATION + SPLIT_ALL = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED + + # Words forcibly split by Text::Format will be stored as split words. + # This class represents a word forcibly split. + class SplitWord + # The word that was split. + attr_reader :word + # The first part of the word that was split. + attr_reader :first + # The remainder of the word that was split. + attr_reader :rest + + def initialize(word, first, rest) #:nodoc: + @word = word + @first = first + @rest = rest + end + end + + private + LEQ_RE = /[.?!]['"]?$/ + + def brk_re(i) #:nodoc: + %r/((?:\S+\s+){#{i}})(.+)/ + end + + def posint(p) #:nodoc: + p.to_i.abs + end + + public + # Compares two Text::Format objects. All settings of the objects are + # compared *except* #hyphenator. Generated results (e.g., #split_words) + # are not compared, either. + def ==(o) + (@text == o.text) && + (@columns == o.columns) && + (@left_margin == o.left_margin) && + (@right_margin == o.right_margin) && + (@hard_margins == o.hard_margins) && + (@split_rules == o.split_rules) && + (@first_indent == o.first_indent) && + (@body_indent == o.body_indent) && + (@tag_text == o.tag_text) && + (@tabstop == o.tabstop) && + (@format_style == o.format_style) && + (@extra_space == o.extra_space) && + (@tag_paragraph == o.tag_paragraph) && + (@nobreak == o.nobreak) && + (@abbreviations == o.abbreviations) && + (@nobreak_regex == o.nobreak_regex) + end + + # The text to be manipulated. Note that value is optional, but if the + # formatting functions are called without values, this text is what will + # be formatted. + # + # *Default*:: [] + # Used in:: All methods + attr_accessor :text + + # The total width of the format area. The margins, indentation, and text + # are formatted into this space. + # + # COLUMNS + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here right margin + # + # *Default*:: 72 + # Used in:: #format, #paragraphs, + # #center + attr_reader :columns + + # The total width of the format area. The margins, indentation, and text + # are formatted into this space. The value provided is silently + # converted to a positive integer. + # + # COLUMNS + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here right margin + # + # *Default*:: 72 + # Used in:: #format, #paragraphs, + # #center + def columns=(c) + @columns = posint(c) + end + + # The number of spaces used for the left margin. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # LEFT MARGIN indent text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + attr_reader :left_margin + + # The number of spaces used for the left margin. The value provided is + # silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # LEFT MARGIN indent text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + def left_margin=(left) + @left_margin = posint(left) + end + + # The number of spaces used for the right margin. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here RIGHT MARGIN + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + attr_reader :right_margin + + # The number of spaces used for the right margin. The value provided is + # silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here RIGHT MARGIN + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + def right_margin=(r) + @right_margin = posint(r) + end + + # The number of spaces to indent the first line of a paragraph. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 4 + # Used in:: #format, #paragraphs + attr_reader :first_indent + + # The number of spaces to indent the first line of a paragraph. The + # value provided is silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 4 + # Used in:: #format, #paragraphs + def first_indent=(f) + @first_indent = posint(f) + end + + # The number of spaces to indent all lines after the first line of a + # paragraph. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs + attr_reader :body_indent + + # The number of spaces to indent all lines after the first line of + # a paragraph. The value provided is silently converted to a + # positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs + def body_indent=(b) + @body_indent = posint(b) + end + + # Normally, words larger than the format area will be placed on a line + # by themselves. Setting this to +true+ will force words larger than the + # format area to be split into one or more "words" each at most the size + # of the format area. The first line and the original word will be + # placed into #split_words. Note that this will cause the + # output to look *similar* to a #format_style of JUSTIFY. (Lines will be + # filled as much as possible.) + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :hard_margins + + # An array of words split during formatting if #hard_margins is set to + # +true+. + # #split_words << Text::Format::SplitWord.new(word, first, rest) + attr_reader :split_words + + # The object responsible for hyphenating. It must respond to + # #hyphenate_to(word, size) or #hyphenate_to(word, size, formatter) and + # return an array of the word split into two parts; if there is a + # hyphenation mark to be applied, responsibility belongs to the + # hyphenator object. The size is the MAXIMUM size permitted, including + # any hyphenation marks. If the #hyphenate_to method has an arity of 3, + # the formatter will be provided to the method. This allows the + # hyphenator to make decisions about the hyphenation based on the + # formatting rules. + # + # *Default*:: +nil+ + # Used in:: #format, #paragraphs + attr_reader :hyphenator + + # The object responsible for hyphenating. It must respond to + # #hyphenate_to(word, size) and return an array of the word hyphenated + # into two parts. The size is the MAXIMUM size permitted, including any + # hyphenation marks. + # + # *Default*:: +nil+ + # Used in:: #format, #paragraphs + def hyphenator=(h) + raise ArgumentError, "#{h.inspect} is not a valid hyphenator." unless h.respond_to?(:hyphenate_to) + arity = h.method(:hyphenate_to).arity + raise ArgumentError, "#{h.inspect} must have exactly two or three arguments." unless [2, 3].include?(arity) + @hyphenator = h + @hyphenator_arity = arity + end + + # Specifies the split mode; used only when #hard_margins is set to + # +true+. Allowable values are: + # [+SPLIT_FIXED+] The word will be split at the number of + # characters needed, with no marking at all. + # repre + # senta + # ion + # [+SPLIT_CONTINUATION+] The word will be split at the number of + # characters needed, with a C-style continuation + # character. If a word is the only item on a + # line and it cannot be split into an + # appropriate size, SPLIT_FIXED will be used. + # repr\ + # esen\ + # tati\ + # on + # [+SPLIT_HYPHENATION+] The word will be split according to the + # hyphenator specified in #hyphenator. If there + # is no #hyphenator specified, works like + # SPLIT_CONTINUATION. The example is using + # TeX::Hyphen. If a word is the only item on a + # line and it cannot be split into an + # appropriate size, SPLIT_CONTINUATION mode will + # be used. + # rep- + # re- + # sen- + # ta- + # tion + # + # *Default*:: Text::Format::SPLIT_FIXED + # Used in:: #format, #paragraphs + attr_reader :split_rules + + # Specifies the split mode; used only when #hard_margins is set to + # +true+. Allowable values are: + # [+SPLIT_FIXED+] The word will be split at the number of + # characters needed, with no marking at all. + # repre + # senta + # ion + # [+SPLIT_CONTINUATION+] The word will be split at the number of + # characters needed, with a C-style continuation + # character. + # repr\ + # esen\ + # tati\ + # on + # [+SPLIT_HYPHENATION+] The word will be split according to the + # hyphenator specified in #hyphenator. If there + # is no #hyphenator specified, works like + # SPLIT_CONTINUATION. The example is using + # TeX::Hyphen as the #hyphenator. + # rep- + # re- + # sen- + # ta- + # tion + # + # These values can be bitwise ORed together (e.g., SPLIT_FIXED | + # SPLIT_CONTINUATION) to provide fallback split methods. In the + # example given, an attempt will be made to split the word using the + # rules of SPLIT_CONTINUATION; if there is not enough room, the word + # will be split with the rules of SPLIT_FIXED. These combinations are + # also available as the following values: + # * +SPLIT_CONTINUATION_FIXED+ + # * +SPLIT_HYPHENATION_FIXED+ + # * +SPLIT_HYPHENATION_CONTINUATION+ + # * +SPLIT_ALL+ + # + # *Default*:: Text::Format::SPLIT_FIXED + # Used in:: #format, #paragraphs + def split_rules=(s) + raise ArgumentError, "Invalid value provided for split_rules." if ((s < SPLIT_FIXED) || (s > SPLIT_ALL)) + @split_rules = s + end + + # Indicates whether sentence terminators should be followed by a single + # space (+false+), or two spaces (+true+). + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :extra_space + + # Defines the current abbreviations as an array. This is only used if + # extra_space is turned on. + # + # If one is abbreviating "President" as "Pres." (abbreviations = + # ["Pres"]), then the results of formatting will be as illustrated in + # the table below: + # + # extra_space | include? | !include? + # true | Pres. Lincoln | Pres. Lincoln + # false | Pres. Lincoln | Pres. Lincoln + # + # *Default*:: {} + # Used in:: #format, #paragraphs + attr_accessor :abbreviations + + # Indicates whether the formatting of paragraphs should be done with + # tagged paragraphs. Useful only with #tag_text. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :tag_paragraph + + # The array of text to be placed before each paragraph when + # #tag_paragraph is +true+. When #format() is called, + # only the first element of the array is used. When #paragraphs + # is called, then each entry in the array will be used once, with + # corresponding paragraphs. If the tag elements are exhausted before the + # text is exhausted, then the remaining paragraphs will not be tagged. + # Regardless of indentation settings, a blank line will be inserted + # between all paragraphs when #tag_paragraph is +true+. + # + # *Default*:: [] + # Used in:: #format, #paragraphs + attr_accessor :tag_text + + # Indicates whether or not the non-breaking space feature should be + # used. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :nobreak + + # A hash which holds the regular expressions on which spaces should not + # be broken. The hash is set up such that the key is the first word and + # the value is the second word. + # + # For example, if +nobreak_regex+ contains the following hash: + # + # { '^Mrs?\.$' => '\S+$', '^\S+$' => '^(?:S|J)r\.$'} + # + # Then "Mr. Jones", "Mrs. Jones", and "Jones Jr." would not be broken. + # If this simple matching algorithm indicates that there should not be a + # break at the current end of line, then a backtrack is done until there + # are two words on which line breaking is permitted. If two such words + # are not found, then the end of the line will be broken *regardless*. + # If there is a single word on the current line, then no backtrack is + # done and the word is stuck on the end. + # + # *Default*:: {} + # Used in:: #format, #paragraphs + attr_accessor :nobreak_regex + + # Indicates the number of spaces that a single tab represents. + # + # *Default*:: 8 + # Used in:: #expand, #unexpand, + # #paragraphs + attr_reader :tabstop + + # Indicates the number of spaces that a single tab represents. + # + # *Default*:: 8 + # Used in:: #expand, #unexpand, + # #paragraphs + def tabstop=(t) + @tabstop = posint(t) + end + + # Specifies the format style. Allowable values are: + # [+LEFT_ALIGN+] Left justified, ragged right. + # |A paragraph that is| + # |left aligned.| + # [+RIGHT_ALIGN+] Right justified, ragged left. + # |A paragraph that is| + # | right aligned.| + # [+RIGHT_FILL+] Left justified, right ragged, filled to width by + # spaces. (Essentially the same as +LEFT_ALIGN+ except + # that lines are padded on the right.) + # |A paragraph that is| + # |left aligned. | + # [+JUSTIFY+] Fully justified, words filled to width by spaces, + # except the last line. + # |A paragraph that| + # |is justified.| + # + # *Default*:: Text::Format::LEFT_ALIGN + # Used in:: #format, #paragraphs + attr_reader :format_style + + # Specifies the format style. Allowable values are: + # [+LEFT_ALIGN+] Left justified, ragged right. + # |A paragraph that is| + # |left aligned.| + # [+RIGHT_ALIGN+] Right justified, ragged left. + # |A paragraph that is| + # | right aligned.| + # [+RIGHT_FILL+] Left justified, right ragged, filled to width by + # spaces. (Essentially the same as +LEFT_ALIGN+ except + # that lines are padded on the right.) + # |A paragraph that is| + # |left aligned. | + # [+JUSTIFY+] Fully justified, words filled to width by spaces. + # |A paragraph that| + # |is justified.| + # + # *Default*:: Text::Format::LEFT_ALIGN + # Used in:: #format, #paragraphs + def format_style=(fs) + raise ArgumentError, "Invalid value provided for format_style." if ((fs < LEFT_ALIGN) || (fs > JUSTIFY)) + @format_style = fs + end + + # Indicates that the format style is left alignment. + # + # *Default*:: +true+ + # Used in:: #format, #paragraphs + def left_align? + return @format_style == LEFT_ALIGN + end + + # Indicates that the format style is right alignment. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def right_align? + return @format_style == RIGHT_ALIGN + end + + # Indicates that the format style is right fill. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def right_fill? + return @format_style == RIGHT_FILL + end + + # Indicates that the format style is full justification. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def justify? + return @format_style == JUSTIFY + end + + # The default implementation of #hyphenate_to implements + # SPLIT_CONTINUATION. + def hyphenate_to(word, size) + [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]] + end + + private + def __do_split_word(word, size) #:nodoc: + [word[0 .. (size - 1)], word[size .. -1]] + end + + def __format(to_wrap) #:nodoc: + words = to_wrap.split(/\s+/).compact + words.shift if words[0].nil? or words[0].empty? + to_wrap = [] + + abbrev = false + width = @columns - @first_indent - @left_margin - @right_margin + indent_str = ' ' * @first_indent + first_line = true + line = words.shift + abbrev = __is_abbrev(line) unless line.nil? || line.empty? + + while w = words.shift + if (w.size + line.size < (width - 1)) || + ((line !~ LEQ_RE || abbrev) && (w.size + line.size < width)) + line << " " if (line =~ LEQ_RE) && (not abbrev) + line << " #{w}" + else + line, w = __do_break(line, w) if @nobreak + line, w = __do_hyphenate(line, w, width) if @hard_margins + if w.index(/\s+/) + w, *w2 = w.split(/\s+/) + words.unshift(w2) + words.flatten! + end + to_wrap << __make_line(line, indent_str, width, w.nil?) unless line.nil? + if first_line + first_line = false + width = @columns - @body_indent - @left_margin - @right_margin + indent_str = ' ' * @body_indent + end + line = w + end + + abbrev = __is_abbrev(w) unless w.nil? + end + + loop do + break if line.nil? or line.empty? + line, w = __do_hyphenate(line, w, width) if @hard_margins + to_wrap << __make_line(line, indent_str, width, w.nil?) + line = w + end + + if (@tag_paragraph && (to_wrap.size > 0)) then + clr = %r{`(\w+)'}.match([caller(1)].flatten[0])[1] + clr = "" if clr.nil? + + if ((not @tag_text[0].nil?) && (@tag_cur.size < 1) && + (clr != "__paragraphs")) then + @tag_cur = @tag_text[0] + end + + fchar = /(\S)/.match(to_wrap[0])[1] + white = to_wrap[0].index(fchar) + if ((white - @left_margin - 1) > @tag_cur.size) then + white = @tag_cur.size + @left_margin + to_wrap[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}") + else + to_wrap.unshift("#{' ' * @left_margin}#{@tag_cur}\n") + end + end + to_wrap.join('') + end + + # format lines in text into paragraphs with each element of @wrap a + # paragraph; uses Text::Format.format for the formatting + def __paragraphs(to_wrap) #:nodoc: + if ((@first_indent == @body_indent) || @tag_paragraph) then + p_end = "\n" + else + p_end = '' + end + + cnt = 0 + ret = [] + to_wrap.each do |tw| + @tag_cur = @tag_text[cnt] if @tag_paragraph + @tag_cur = '' if @tag_cur.nil? + line = __format(tw) + ret << "#{line}#{p_end}" if (not line.nil?) && (line.size > 0) + cnt += 1 + end + + ret[-1].chomp! unless ret.empty? + ret.join('') + end + + # center text using spaces on left side to pad it out empty lines + # are preserved + def __center(to_center) #:nodoc: + tabs = 0 + width = @columns - @left_margin - @right_margin + centered = [] + to_center.each do |tc| + s = tc.strip + tabs = s.count("\t") + tabs = 0 if tabs.nil? + ct = ((width - s.size - (tabs * @tabstop) + tabs) / 2) + ct = (width - @left_margin - @right_margin) - ct + centered << "#{s.rjust(ct)}\n" + end + centered.join('') + end + + # expand tabs to spaces should be similar to Text::Tabs::expand + def __expand(to_expand) #:nodoc: + expanded = [] + to_expand.split("\n").each { |te| expanded << te.gsub(/\t/, ' ' * @tabstop) } + expanded.join('') + end + + def __unexpand(to_unexpand) #:nodoc: + unexpanded = [] + to_unexpand.split("\n").each { |tu| unexpanded << tu.gsub(/ {#{@tabstop}}/, "\t") } + unexpanded.join('') + end + + def __is_abbrev(word) #:nodoc: + # remove period if there is one. + w = word.gsub(/\.$/, '') unless word.nil? + return true if (!@extra_space || ABBREV.include?(w) || @abbreviations.include?(w)) + false + end + + def __make_line(line, indent, width, last = false) #:nodoc: + lmargin = " " * @left_margin + fill = " " * (width - line.size) if right_fill? && (line.size <= width) + + if (justify? && ((not line.nil?) && (not line.empty?)) && line =~ /\S+\s+\S+/ && !last) + spaces = width - line.size + words = line.split(/(\s+)/) + ws = spaces / (words.size / 2) + spaces = spaces % (words.size / 2) if ws > 0 + words.reverse.each do |rw| + next if (rw =~ /^\S/) + rw.sub!(/^/, " " * ws) + next unless (spaces > 0) + rw.sub!(/^/, " ") + spaces -= 1 + end + line = words.join('') + end + line = "#{lmargin}#{indent}#{line}#{fill}\n" unless line.nil? + if right_align? && (not line.nil?) + line.sub(/^/, " " * (@columns - @right_margin - (line.size - 1))) + else + line + end + end + + def __do_hyphenate(line, next_line, width) #:nodoc: + rline = line.dup rescue line + rnext = next_line.dup rescue next_line + loop do + if rline.size == width + break + elsif rline.size > width + words = rline.strip.split(/\s+/) + word = words[-1].dup + size = width - rline.size + word.size + if (size <= 0) + words[-1] = nil + rline = words.join(' ').strip + rnext = "#{word} #{rnext}".strip + next + end + + first = rest = nil + + if ((@split_rules & SPLIT_HYPHENATION) != 0) + if @hyphenator_arity == 2 + first, rest = @hyphenator.hyphenate_to(word, size) + else + first, rest = @hyphenator.hyphenate_to(word, size, self) + end + end + + if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? + first, rest = self.hyphenate_to(word, size) + end + + if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? + first.nil? or @split_rules == SPLIT_FIXED + first, rest = __do_split_word(word, size) + end + + if first.nil? + words[-1] = nil + rest = word + else + words[-1] = first + @split_words << SplitWord.new(word, first, rest) + end + rline = words.join(' ').strip + rnext = "#{rest} #{rnext}".strip + break + else + break if rnext.nil? or rnext.empty? or rline.nil? or rline.empty? + words = rnext.split(/\s+/) + word = words.shift + size = width - rline.size - 1 + + if (size <= 0) + rnext = "#{word} #{words.join(' ')}".strip + break + end + + first = rest = nil + + if ((@split_rules & SPLIT_HYPHENATION) != 0) + if @hyphenator_arity == 2 + first, rest = @hyphenator.hyphenate_to(word, size) + else + first, rest = @hyphenator.hyphenate_to(word, size, self) + end + end + + first, rest = self.hyphenate_to(word, size) if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? + + first, rest = __do_split_word(word, size) if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? + + if (rline.size + (first ? first.size : 0)) < width + @split_words << SplitWord.new(word, first, rest) + rline = "#{rline} #{first}".strip + rnext = "#{rest} #{words.join(' ')}".strip + end + break + end + end + [rline, rnext] + end + + def __do_break(line, next_line) #:nodoc: + no_brk = false + words = [] + words = line.split(/\s+/) unless line.nil? + last_word = words[-1] + + @nobreak_regex.each { |k, v| no_brk = ((last_word =~ /#{k}/) and (next_line =~ /#{v}/)) } + + if no_brk && words.size > 1 + i = words.size + while i > 0 + no_brk = false + @nobreak_regex.each { |k, v| no_brk = ((words[i + 1] =~ /#{k}/) && (words[i] =~ /#{v}/)) } + i -= 1 + break if not no_brk + end + if i > 0 + l = brk_re(i).match(line) + line.sub!(brk_re(i), l[1]) + next_line = "#{l[2]} #{next_line}" + line.sub!(/\s+$/, '') + end + end + [line, next_line] + end + + def __create(arg = nil, &block) #:nodoc: + # Format::Text.new(text-to-wrap) + @text = arg unless arg.nil? + # Defaults + @columns = 72 + @tabstop = 8 + @first_indent = 4 + @body_indent = 0 + @format_style = LEFT_ALIGN + @left_margin = 0 + @right_margin = 0 + @extra_space = false + @text = Array.new if @text.nil? + @tag_paragraph = false + @tag_text = Array.new + @tag_cur = "" + @abbreviations = Array.new + @nobreak = false + @nobreak_regex = Hash.new + @split_words = Array.new + @hard_margins = false + @split_rules = SPLIT_FIXED + @hyphenator = self + @hyphenator_arity = self.method(:hyphenate_to).arity + + instance_eval(&block) unless block.nil? + end + + public + # Formats text into a nice paragraph format. The text is separated + # into words and then reassembled a word at a time using the settings + # of this Format object. If a word is larger than the number of + # columns available for formatting, then that word will appear on the + # line by itself. + # + # If +to_wrap+ is +nil+, then the value of #text will be + # worked on. + def format(to_wrap = nil) + to_wrap = @text if to_wrap.nil? + if to_wrap.class == Array + __format(to_wrap[0]) + else + __format(to_wrap) + end + end + + # Considers each element of text (provided or internal) as a paragraph. + # If #first_indent is the same as #body_indent, then + # paragraphs will be separated by a single empty line in the result; + # otherwise, the paragraphs will follow immediately after each other. + # Uses #format to do the heavy lifting. + def paragraphs(to_wrap = nil) + to_wrap = @text if to_wrap.nil? + __paragraphs([to_wrap].flatten) + end + + # Centers the text, preserving empty lines and tabs. + def center(to_center = nil) + to_center = @text if to_center.nil? + __center([to_center].flatten) + end + + # Replaces all tab characters in the text with #tabstop spaces. + def expand(to_expand = nil) + to_expand = @text if to_expand.nil? + if to_expand.class == Array + to_expand.collect { |te| __expand(te) } + else + __expand(to_expand) + end + end + + # Replaces all occurrences of #tabstop consecutive spaces + # with a tab character. + def unexpand(to_unexpand = nil) + to_unexpand = @text if to_unexpand.nil? + if to_unexpand.class == Array + to_unexpand.collect { |te| v << __unexpand(te) } + else + __unexpand(to_unexpand) + end + end + + # This constructor takes advantage of a technique for Ruby object + # construction introduced by Andy Hunt and Dave Thomas (see reference), + # where optional values are set using commands in a block. + # + # Text::Format.new { + # columns = 72 + # left_margin = 0 + # right_margin = 0 + # first_indent = 4 + # body_indent = 0 + # format_style = Text::Format::LEFT_ALIGN + # extra_space = false + # abbreviations = {} + # tag_paragraph = false + # tag_text = [] + # nobreak = false + # nobreak_regex = {} + # tabstop = 8 + # text = nil + # } + # + # As shown above, +arg+ is optional. If +arg+ is specified and is a + # +String+, then arg is used as the default value of #text. + # Alternately, an existing Text::Format object can be used or a Hash can + # be used. With all forms, a block can be specified. + # + # *Reference*:: "Object Construction and Blocks" + # + # + def initialize(arg = nil, &block) + @text = nil + case arg + when Text::Format + __create(arg.text) do + @columns = arg.columns + @tabstop = arg.tabstop + @first_indent = arg.first_indent + @body_indent = arg.body_indent + @format_style = arg.format_style + @left_margin = arg.left_margin + @right_margin = arg.right_margin + @extra_space = arg.extra_space + @tag_paragraph = arg.tag_paragraph + @tag_text = arg.tag_text + @abbreviations = arg.abbreviations + @nobreak = arg.nobreak + @nobreak_regex = arg.nobreak_regex + @text = arg.text + @hard_margins = arg.hard_margins + @split_words = arg.split_words + @split_rules = arg.split_rules + @hyphenator = arg.hyphenator + end + instance_eval(&block) unless block.nil? + when Hash + __create do + @columns = arg[:columns] || arg['columns'] || @columns + @tabstop = arg[:tabstop] || arg['tabstop'] || @tabstop + @first_indent = arg[:first_indent] || arg['first_indent'] || @first_indent + @body_indent = arg[:body_indent] || arg['body_indent'] || @body_indent + @format_style = arg[:format_style] || arg['format_style'] || @format_style + @left_margin = arg[:left_margin] || arg['left_margin'] || @left_margin + @right_margin = arg[:right_margin] || arg['right_margin'] || @right_margin + @extra_space = arg[:extra_space] || arg['extra_space'] || @extra_space + @text = arg[:text] || arg['text'] || @text + @tag_paragraph = arg[:tag_paragraph] || arg['tag_paragraph'] || @tag_paragraph + @tag_text = arg[:tag_text] || arg['tag_text'] || @tag_text + @abbreviations = arg[:abbreviations] || arg['abbreviations'] || @abbreviations + @nobreak = arg[:nobreak] || arg['nobreak'] || @nobreak + @nobreak_regex = arg[:nobreak_regex] || arg['nobreak_regex'] || @nobreak_regex + @hard_margins = arg[:hard_margins] || arg['hard_margins'] || @hard_margins + @split_rules = arg[:split_rules] || arg['split_rules'] || @split_rules + @hyphenator = arg[:hyphenator] || arg['hyphenator'] || @hyphenator + end + instance_eval(&block) unless block.nil? + when String + __create(arg, &block) + when NilClass + __create(&block) + else + raise TypeError + end + end + end +end + +if __FILE__ == $0 + require 'test/unit' + + class TestText__Format < Test::Unit::TestCase #:nodoc: + attr_accessor :format_o + + GETTYSBURG = <<-'EOS' + Four score and seven years ago our fathers brought forth on this + continent a new nation, conceived in liberty and dedicated to the + proposition that all men are created equal. Now we are engaged in + a great civil war, testing whether that nation or any nation so + conceived and so dedicated can long endure. We are met on a great + battlefield of that war. We have come to dedicate a portion of + that field as a final resting-place for those who here gave their + lives that that nation might live. It is altogether fitting and + proper that we should do this. But in a larger sense, we cannot + dedicate, we cannot consecrate, we cannot hallow this ground. + The brave men, living and dead who struggled here have consecrated + it far above our poor power to add or detract. The world will + little note nor long remember what we say here, but it can never + forget what they did here. It is for us the living rather to be + dedicated here to the unfinished work which they who fought here + have thus far so nobly advanced. It is rather for us to be here + dedicated to the great task remaining before us--that from these + honored dead we take increased devotion to that cause for which + they gave the last full measure of devotion--that we here highly + resolve that these dead shall not have died in vain, that this + nation under God shall have a new birth of freedom, and that + government of the people, by the people, for the people shall + not perish from the earth. + + -- Pres. Abraham Lincoln, 19 November 1863 + EOS + + 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" + + 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" + + # Tests both abbreviations and abbreviations= + def test_abbreviations + abbr = [" Pres. Abraham Lincoln\n", " Pres. Abraham Lincoln\n"] + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.abbreviations) + assert_nothing_raised { @format_o.abbreviations = [ 'foo', 'bar' ] } + assert_equal([ 'foo', 'bar' ], @format_o.abbreviations) + assert_equal(abbr[0], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.extra_space = true } + assert_equal(abbr[1], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.abbreviations = [ "Pres" ] } + assert_equal([ "Pres" ], @format_o.abbreviations) + assert_equal(abbr[0], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.extra_space = false } + assert_equal(abbr[0], @format_o.format(abbr[0])) + end + + # Tests both body_indent and body_indent= + def test_body_indent + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = 7 } + assert_equal(7, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = -3 } + assert_equal(3, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = "9" } + assert_equal(9, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = "-2" } + assert_equal(2, @format_o.body_indent) + assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[1]) + end + + # Tests both columns and columns= + def test_columns + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(72, @format_o.columns) + assert_nothing_raised { @format_o.columns = 7 } + assert_equal(7, @format_o.columns) + assert_nothing_raised { @format_o.columns = -3 } + assert_equal(3, @format_o.columns) + assert_nothing_raised { @format_o.columns = "9" } + assert_equal(9, @format_o.columns) + assert_nothing_raised { @format_o.columns = "-2" } + assert_equal(2, @format_o.columns) + assert_nothing_raised { @format_o.columns = 40 } + assert_equal(40, @format_o.columns) + assert_match(/this continent$/, + @format_o.format(GETTYSBURG).split("\n")[1]) + end + + # Tests both extra_space and extra_space= + def test_extra_space + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.extra_space) + assert_nothing_raised { @format_o.extra_space = true } + assert(@format_o.extra_space) + # The behaviour of extra_space is tested in test_abbreviations. There + # is no need to reproduce it here. + end + + # Tests both first_indent and first_indent= + def test_first_indent + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(4, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = 7 } + assert_equal(7, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = -3 } + assert_equal(3, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = "9" } + assert_equal(9, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = "-2" } + assert_equal(2, @format_o.first_indent) + assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[0]) + end + + def test_format_style + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(Text::Format::LEFT_ALIGN, @format_o.format_style) + assert_match(/^November 1863$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert_equal(Text::Format::RIGHT_ALIGN, @format_o.format_style) + assert_match(/^ +November 1863$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert_equal(Text::Format::RIGHT_FILL, @format_o.format_style) + assert_match(/^November 1863 +$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert_equal(Text::Format::JUSTIFY, @format_o.format_style) + assert_match(/^of freedom, and that government of the people, by the people, for the$/, + @format_o.format(GETTYSBURG).split("\n")[-3]) + assert_raise(ArgumentError) { @format_o.format_style = 33 } + end + + def test_tag_paragraph + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.tag_paragraph) + assert_nothing_raised { @format_o.tag_paragraph = true } + assert(@format_o.tag_paragraph) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) + end + + def test_tag_text + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.tag_text) + assert_equal(@format_o.format(GETTYSBURG), + Text::Format.new.format(GETTYSBURG)) + assert_nothing_raised { + @format_o.tag_paragraph = true + @format_o.tag_text = ["Gettysburg Address", "---"] + } + assert_not_equal(@format_o.format(GETTYSBURG), + Text::Format.new.format(GETTYSBURG)) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG, + GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG, + GETTYSBURG])) + end + + def test_justify? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::JUSTIFY + } + assert(@format_o.justify?) + # The format testing is done in test_format_style + end + + def test_left_align? + assert_nothing_raised { @format_o = Text::Format.new } + assert(@format_o.left_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.left_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.left_align?) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert(!@format_o.left_align?) + # The format testing is done in test_format_style + end + + def test_left_margin + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = -3 } + assert_equal(3, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = "9" } + assert_equal(9, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = "-2" } + assert_equal(2, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = 7 } + assert_equal(7, @format_o.left_margin) + assert_nothing_raised { + ft = @format_o.format(GETTYSBURG).split("\n") + assert_match(/^ {11}Four score/, ft[0]) + assert_match(/^ {7}November/, ft[-1]) + } + end + + def test_hard_margins + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.hard_margins) + assert_nothing_raised { + @format_o.hard_margins = true + @format_o.columns = 5 + @format_o.first_indent = 0 + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(@format_o.hard_margins) + assert_equal(FIVE_COL, @format_o.format(GETTYSBURG)) + assert_nothing_raised { + @format_o.split_rules |= Text::Format::SPLIT_CONTINUATION + assert_equal(Text::Format::SPLIT_CONTINUATION_FIXED, + @format_o.split_rules) + } + assert_equal(FIVE_CNT, @format_o.format(GETTYSBURG)) + end + + # Tests both nobreak and nobreak_regex, since one is only useful + # with the other. + def test_nobreak + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.nobreak) + assert(@format_o.nobreak_regex.empty?) + assert_nothing_raised { + @format_o.nobreak = true + @format_o.nobreak_regex = { '^this$' => '^continent$' } + @format_o.columns = 77 + } + assert(@format_o.nobreak) + assert_equal({ '^this$' => '^continent$' }, @format_o.nobreak_regex) + assert_match(/^this continent/, + @format_o.format(GETTYSBURG).split("\n")[1]) + end + + def test_right_align? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.right_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(@format_o.right_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.right_align?) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert(!@format_o.right_align?) + # The format testing is done in test_format_style + end + + def test_right_fill? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::JUSTIFY + } + assert(!@format_o.right_fill?) + # The format testing is done in test_format_style + end + + def test_right_margin + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = -3 } + assert_equal(3, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = "9" } + assert_equal(9, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = "-2" } + assert_equal(2, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = 7 } + assert_equal(7, @format_o.right_margin) + assert_nothing_raised { + ft = @format_o.format(GETTYSBURG).split("\n") + assert_match(/^ {4}Four score.*forth on$/, ft[0]) + assert_match(/^November/, ft[-1]) + } + end + + def test_tabstop + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(8, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = 7 } + assert_equal(7, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = -3 } + assert_equal(3, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = "9" } + assert_equal(9, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = "-2" } + assert_equal(2, @format_o.tabstop) + end + + def test_text + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.text) + assert_nothing_raised { @format_o.text = "Test Text" } + assert_equal("Test Text", @format_o.text) + assert_nothing_raised { @format_o.text = ["Line 1", "Line 2"] } + assert_equal(["Line 1", "Line 2"], @format_o.text) + end + + def test_s_new + # new(NilClass) { block } + assert_nothing_raised do + @format_o = Text::Format.new { + self.text = "Test 1, 2, 3" + } + end + assert_equal("Test 1, 2, 3", @format_o.text) + + # new(Hash Symbols) + assert_nothing_raised { @format_o = Text::Format.new(:columns => 72) } + assert_equal(72, @format_o.columns) + + # new(Hash String) + assert_nothing_raised { @format_o = Text::Format.new('columns' => 72) } + assert_equal(72, @format_o.columns) + + # new(Hash) { block } + assert_nothing_raised do + @format_o = Text::Format.new('columns' => 80) { + self.text = "Test 4, 5, 6" + } + end + assert_equal("Test 4, 5, 6", @format_o.text) + assert_equal(80, @format_o.columns) + + # new(Text::Format) + assert_nothing_raised do + fo = Text::Format.new(@format_o) + assert(fo == @format_o) + end + + # new(Text::Format) { block } + assert_nothing_raised do + fo = Text::Format.new(@format_o) { self.columns = 79 } + assert(fo != @format_o) + end + + # new(String) + assert_nothing_raised { @format_o = Text::Format.new("Test A, B, C") } + assert_equal("Test A, B, C", @format_o.text) + + # new(String) { block } + assert_nothing_raised do + @format_o = Text::Format.new("Test X, Y, Z") { self.columns = -5 } + end + assert_equal("Test X, Y, Z", @format_o.text) + assert_equal(5, @format_o.columns) + end + + def test_center + assert_nothing_raised { @format_o = Text::Format.new } + assert_nothing_raised do + ct = @format_o.center(GETTYSBURG.split("\n")).split("\n") + assert_match(/^ Four score and seven years ago our fathers brought forth on this/, ct[0]) + assert_match(/^ not perish from the earth./, ct[-3]) + end + end + + def test_expand + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(" ", @format_o.expand("\t ")) + assert_nothing_raised { @format_o.tabstop = 4 } + assert_equal(" ", @format_o.expand("\t ")) + end + + def test_unexpand + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal("\t ", @format_o.unexpand(" ")) + assert_nothing_raised { @format_o.tabstop = 4 } + assert_equal("\t ", @format_o.unexpand(" ")) + end + + def test_space_only + assert_equal("", Text::Format.new.format(" ")) + assert_equal("", Text::Format.new.format("\n")) + assert_equal("", Text::Format.new.format(" ")) + assert_equal("", Text::Format.new.format(" \n")) + assert_equal("", Text::Format.new.paragraphs("\n")) + assert_equal("", Text::Format.new.paragraphs(" ")) + assert_equal("", Text::Format.new.paragraphs(" ")) + assert_equal("", Text::Format.new.paragraphs(" \n")) + assert_equal("", Text::Format.new.paragraphs(["\n"])) + assert_equal("", Text::Format.new.paragraphs([" "])) + assert_equal("", Text::Format.new.paragraphs([" "])) + assert_equal("", Text::Format.new.paragraphs([" \n"])) + end + + def test_splendiferous + h = nil + test = "This is a splendiferous test" + assert_nothing_raised { @format_o = Text::Format.new(:columns => 6, :left_margin => 0, :indent => 0, :first_indent => 0) } + assert_match(/^splendiferous$/, @format_o.format(test)) + assert_nothing_raised { @format_o.hard_margins = true } + assert_match(/^lendif$/, @format_o.format(test)) + assert_nothing_raised { h = Object.new } + assert_nothing_raised do + @format_o.split_rules = Text::Format::SPLIT_HYPHENATION + class << h #:nodoc: + def hyphenate_to(word, size) + return ["", word] if size < 2 + [word[0 ... size], word[size .. -1]] + end + end + @format_o.hyphenator = h + end + assert_match(/^iferou$/, @format_o.format(test)) + assert_nothing_raised { h = Object.new } + assert_nothing_raised do + class << h #:nodoc: + def hyphenate_to(word, size, formatter) + return ["", word] if word.size < formatter.columns + [word[0 ... size], word[size .. -1]] + end + end + @format_o.hyphenator = h + end + assert_match(/^ferous$/, @format_o.format(test)) + end + end +end -- cgit v1.2.3 From a0f44fe0fb0e2ba193a0e1875ed2283e958ec699 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Fri, 1 Jan 2010 20:45:28 +1100 Subject: Silence warning of missing init on @config --- actionpack/lib/action_view/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index d69e5109fa..4970c768e8 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -274,6 +274,7 @@ module ActionView #:nodoc: end def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc: + @config = nil @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @controller = controller -- cgit v1.2.3 From a00923909267781ef67f87fbdcee665f3300e9f9 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Fri, 1 Jan 2010 14:44:11 +1100 Subject: Silence @text not initialized warning --- .../vendor/text-format-0.6.3/text/format.rb | 2933 ++++++++++---------- 1 file changed, 1467 insertions(+), 1466 deletions(-) diff --git a/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb b/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb index 2d20c7a6a1..3a0e04bd77 100755 --- a/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +++ b/actionmailer/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb @@ -1,1466 +1,1467 @@ -#-- -# Text::Format for Ruby -# Version 0.63 -# -# Copyright (c) 2002 - 2003 Austin Ziegler -# -# $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $ -# -# ========================================================================== -# Revision History :: -# YYYY.MM.DD Change ID Developer -# Description -# -------------------------------------------------------------------------- -# 2002.10.18 Austin Ziegler -# Fixed a minor problem with tabs not being counted. Changed -# abbreviations from Hash to Array to better suit Ruby's -# capabilities. Fixed problems with the way that Array arguments -# are handled in calls to the major object types, excepting in -# Text::Format#expand and Text::Format#unexpand (these will -# probably need to be fixed). -# 2002.10.30 Austin Ziegler -# Fixed the ordering of the <=> for binary tests. Fixed -# Text::Format#expand and Text::Format#unexpand to handle array -# arguments better. -# 2003.01.24 Austin Ziegler -# Fixed a problem with Text::Format::RIGHT_FILL handling where a -# single word is larger than #columns. Removed Comparable -# capabilities (<=> doesn't make sense; == does). Added Symbol -# equivalents for the Hash initialization. Hash initialization has -# been modified so that values are set as follows (Symbols are -# highest priority; strings are middle; defaults are lowest): -# @columns = arg[:columns] || arg['columns'] || @columns -# Added #hard_margins, #split_rules, #hyphenator, and #split_words. -# 2003.02.07 Austin Ziegler -# Fixed the installer for proper case-sensitive handling. -# 2003.03.28 Austin Ziegler -# Added the ability for a hyphenator to receive the formatter -# object. Fixed a bug for strings matching /\A\s*\Z/ failing -# entirely. Fixed a test case failing under 1.6.8. -# 2003.04.04 Austin Ziegler -# Handle the case of hyphenators returning nil for first/rest. -# 2003.09.17 Austin Ziegler -# Fixed a problem where #paragraphs(" ") was raising -# NoMethodError. -# -# ========================================================================== -#++ - -module Text #:nodoc: - # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It - # is available under Ruby's licence, the Perl Artistic licence, or the - # GNU GPL version 2 (or at your option, any later version). As a - # special exception, for use with official Rails (provided by the - # rubyonrails.org development team) and any project created with - # official Rails, the following alternative MIT-style licence may be - # used: - # - # == Text::Format Licence for Rails and Rails Applications - # Permission is hereby granted, free of charge, to any person - # obtaining a copy of this software and associated documentation files - # (the "Software"), to deal in the Software without restriction, - # including without limitation the rights to use, copy, modify, merge, - # publish, distribute, sublicense, and/or sell copies of the Software, - # and to permit persons to whom the Software is furnished to do so, - # subject to the following conditions: - # - # * The names of its contributors may not be used to endorse or - # promote products derived from this software without specific prior - # written permission. - # - # The above copyright notice and this permission notice shall be - # included in all copies or substantial portions of the Software. - # - # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - # SOFTWARE. - class Format - VERSION = '0.63' - - # Local abbreviations. More can be added with Text::Format.abbreviations - ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ] - - # Formatting values - LEFT_ALIGN = 0 - RIGHT_ALIGN = 1 - RIGHT_FILL = 2 - JUSTIFY = 3 - - # Word split modes (only applies when #hard_margins is true). - SPLIT_FIXED = 1 - SPLIT_CONTINUATION = 2 - SPLIT_HYPHENATION = 4 - SPLIT_CONTINUATION_FIXED = SPLIT_CONTINUATION | SPLIT_FIXED - SPLIT_HYPHENATION_FIXED = SPLIT_HYPHENATION | SPLIT_FIXED - SPLIT_HYPHENATION_CONTINUATION = SPLIT_HYPHENATION | SPLIT_CONTINUATION - SPLIT_ALL = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED - - # Words forcibly split by Text::Format will be stored as split words. - # This class represents a word forcibly split. - class SplitWord - # The word that was split. - attr_reader :word - # The first part of the word that was split. - attr_reader :first - # The remainder of the word that was split. - attr_reader :rest - - def initialize(word, first, rest) #:nodoc: - @word = word - @first = first - @rest = rest - end - end - - private - LEQ_RE = /[.?!]['"]?$/ - - def brk_re(i) #:nodoc: - %r/((?:\S+\s+){#{i}})(.+)/ - end - - def posint(p) #:nodoc: - p.to_i.abs - end - - public - # Compares two Text::Format objects. All settings of the objects are - # compared *except* #hyphenator. Generated results (e.g., #split_words) - # are not compared, either. - def ==(o) - (@text == o.text) && - (@columns == o.columns) && - (@left_margin == o.left_margin) && - (@right_margin == o.right_margin) && - (@hard_margins == o.hard_margins) && - (@split_rules == o.split_rules) && - (@first_indent == o.first_indent) && - (@body_indent == o.body_indent) && - (@tag_text == o.tag_text) && - (@tabstop == o.tabstop) && - (@format_style == o.format_style) && - (@extra_space == o.extra_space) && - (@tag_paragraph == o.tag_paragraph) && - (@nobreak == o.nobreak) && - (@abbreviations == o.abbreviations) && - (@nobreak_regex == o.nobreak_regex) - end - - # The text to be manipulated. Note that value is optional, but if the - # formatting functions are called without values, this text is what will - # be formatted. - # - # *Default*:: [] - # Used in:: All methods - attr_accessor :text - - # The total width of the format area. The margins, indentation, and text - # are formatted into this space. - # - # COLUMNS - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here right margin - # - # *Default*:: 72 - # Used in:: #format, #paragraphs, - # #center - attr_reader :columns - - # The total width of the format area. The margins, indentation, and text - # are formatted into this space. The value provided is silently - # converted to a positive integer. - # - # COLUMNS - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here right margin - # - # *Default*:: 72 - # Used in:: #format, #paragraphs, - # #center - def columns=(c) - @columns = posint(c) - end - - # The number of spaces used for the left margin. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # LEFT MARGIN indent text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - attr_reader :left_margin - - # The number of spaces used for the left margin. The value provided is - # silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # LEFT MARGIN indent text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - def left_margin=(left) - @left_margin = posint(left) - end - - # The number of spaces used for the right margin. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here RIGHT MARGIN - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - attr_reader :right_margin - - # The number of spaces used for the right margin. The value provided is - # silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin indent text is formatted into here RIGHT MARGIN - # - # *Default*:: 0 - # Used in:: #format, #paragraphs, - # #center - def right_margin=(r) - @right_margin = posint(r) - end - - # The number of spaces to indent the first line of a paragraph. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 4 - # Used in:: #format, #paragraphs - attr_reader :first_indent - - # The number of spaces to indent the first line of a paragraph. The - # value provided is silently converted to a positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 4 - # Used in:: #format, #paragraphs - def first_indent=(f) - @first_indent = posint(f) - end - - # The number of spaces to indent all lines after the first line of a - # paragraph. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs - attr_reader :body_indent - - # The number of spaces to indent all lines after the first line of - # a paragraph. The value provided is silently converted to a - # positive integer value. - # - # columns - # <--------------------------------------------------------------> - # <-----------><------><---------------------------><------------> - # left margin INDENT text is formatted into here right margin - # - # *Default*:: 0 - # Used in:: #format, #paragraphs - def body_indent=(b) - @body_indent = posint(b) - end - - # Normally, words larger than the format area will be placed on a line - # by themselves. Setting this to +true+ will force words larger than the - # format area to be split into one or more "words" each at most the size - # of the format area. The first line and the original word will be - # placed into #split_words. Note that this will cause the - # output to look *similar* to a #format_style of JUSTIFY. (Lines will be - # filled as much as possible.) - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :hard_margins - - # An array of words split during formatting if #hard_margins is set to - # +true+. - # #split_words << Text::Format::SplitWord.new(word, first, rest) - attr_reader :split_words - - # The object responsible for hyphenating. It must respond to - # #hyphenate_to(word, size) or #hyphenate_to(word, size, formatter) and - # return an array of the word split into two parts; if there is a - # hyphenation mark to be applied, responsibility belongs to the - # hyphenator object. The size is the MAXIMUM size permitted, including - # any hyphenation marks. If the #hyphenate_to method has an arity of 3, - # the formatter will be provided to the method. This allows the - # hyphenator to make decisions about the hyphenation based on the - # formatting rules. - # - # *Default*:: +nil+ - # Used in:: #format, #paragraphs - attr_reader :hyphenator - - # The object responsible for hyphenating. It must respond to - # #hyphenate_to(word, size) and return an array of the word hyphenated - # into two parts. The size is the MAXIMUM size permitted, including any - # hyphenation marks. - # - # *Default*:: +nil+ - # Used in:: #format, #paragraphs - def hyphenator=(h) - raise ArgumentError, "#{h.inspect} is not a valid hyphenator." unless h.respond_to?(:hyphenate_to) - arity = h.method(:hyphenate_to).arity - raise ArgumentError, "#{h.inspect} must have exactly two or three arguments." unless [2, 3].include?(arity) - @hyphenator = h - @hyphenator_arity = arity - end - - # Specifies the split mode; used only when #hard_margins is set to - # +true+. Allowable values are: - # [+SPLIT_FIXED+] The word will be split at the number of - # characters needed, with no marking at all. - # repre - # senta - # ion - # [+SPLIT_CONTINUATION+] The word will be split at the number of - # characters needed, with a C-style continuation - # character. If a word is the only item on a - # line and it cannot be split into an - # appropriate size, SPLIT_FIXED will be used. - # repr\ - # esen\ - # tati\ - # on - # [+SPLIT_HYPHENATION+] The word will be split according to the - # hyphenator specified in #hyphenator. If there - # is no #hyphenator specified, works like - # SPLIT_CONTINUATION. The example is using - # TeX::Hyphen. If a word is the only item on a - # line and it cannot be split into an - # appropriate size, SPLIT_CONTINUATION mode will - # be used. - # rep- - # re- - # sen- - # ta- - # tion - # - # *Default*:: Text::Format::SPLIT_FIXED - # Used in:: #format, #paragraphs - attr_reader :split_rules - - # Specifies the split mode; used only when #hard_margins is set to - # +true+. Allowable values are: - # [+SPLIT_FIXED+] The word will be split at the number of - # characters needed, with no marking at all. - # repre - # senta - # ion - # [+SPLIT_CONTINUATION+] The word will be split at the number of - # characters needed, with a C-style continuation - # character. - # repr\ - # esen\ - # tati\ - # on - # [+SPLIT_HYPHENATION+] The word will be split according to the - # hyphenator specified in #hyphenator. If there - # is no #hyphenator specified, works like - # SPLIT_CONTINUATION. The example is using - # TeX::Hyphen as the #hyphenator. - # rep- - # re- - # sen- - # ta- - # tion - # - # These values can be bitwise ORed together (e.g., SPLIT_FIXED | - # SPLIT_CONTINUATION) to provide fallback split methods. In the - # example given, an attempt will be made to split the word using the - # rules of SPLIT_CONTINUATION; if there is not enough room, the word - # will be split with the rules of SPLIT_FIXED. These combinations are - # also available as the following values: - # * +SPLIT_CONTINUATION_FIXED+ - # * +SPLIT_HYPHENATION_FIXED+ - # * +SPLIT_HYPHENATION_CONTINUATION+ - # * +SPLIT_ALL+ - # - # *Default*:: Text::Format::SPLIT_FIXED - # Used in:: #format, #paragraphs - def split_rules=(s) - raise ArgumentError, "Invalid value provided for split_rules." if ((s < SPLIT_FIXED) || (s > SPLIT_ALL)) - @split_rules = s - end - - # Indicates whether sentence terminators should be followed by a single - # space (+false+), or two spaces (+true+). - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :extra_space - - # Defines the current abbreviations as an array. This is only used if - # extra_space is turned on. - # - # If one is abbreviating "President" as "Pres." (abbreviations = - # ["Pres"]), then the results of formatting will be as illustrated in - # the table below: - # - # extra_space | include? | !include? - # true | Pres. Lincoln | Pres. Lincoln - # false | Pres. Lincoln | Pres. Lincoln - # - # *Default*:: {} - # Used in:: #format, #paragraphs - attr_accessor :abbreviations - - # Indicates whether the formatting of paragraphs should be done with - # tagged paragraphs. Useful only with #tag_text. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :tag_paragraph - - # The array of text to be placed before each paragraph when - # #tag_paragraph is +true+. When #format() is called, - # only the first element of the array is used. When #paragraphs - # is called, then each entry in the array will be used once, with - # corresponding paragraphs. If the tag elements are exhausted before the - # text is exhausted, then the remaining paragraphs will not be tagged. - # Regardless of indentation settings, a blank line will be inserted - # between all paragraphs when #tag_paragraph is +true+. - # - # *Default*:: [] - # Used in:: #format, #paragraphs - attr_accessor :tag_text - - # Indicates whether or not the non-breaking space feature should be - # used. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - attr_accessor :nobreak - - # A hash which holds the regular expressions on which spaces should not - # be broken. The hash is set up such that the key is the first word and - # the value is the second word. - # - # For example, if +nobreak_regex+ contains the following hash: - # - # { '^Mrs?\.$' => '\S+$', '^\S+$' => '^(?:S|J)r\.$'} - # - # Then "Mr. Jones", "Mrs. Jones", and "Jones Jr." would not be broken. - # If this simple matching algorithm indicates that there should not be a - # break at the current end of line, then a backtrack is done until there - # are two words on which line breaking is permitted. If two such words - # are not found, then the end of the line will be broken *regardless*. - # If there is a single word on the current line, then no backtrack is - # done and the word is stuck on the end. - # - # *Default*:: {} - # Used in:: #format, #paragraphs - attr_accessor :nobreak_regex - - # Indicates the number of spaces that a single tab represents. - # - # *Default*:: 8 - # Used in:: #expand, #unexpand, - # #paragraphs - attr_reader :tabstop - - # Indicates the number of spaces that a single tab represents. - # - # *Default*:: 8 - # Used in:: #expand, #unexpand, - # #paragraphs - def tabstop=(t) - @tabstop = posint(t) - end - - # Specifies the format style. Allowable values are: - # [+LEFT_ALIGN+] Left justified, ragged right. - # |A paragraph that is| - # |left aligned.| - # [+RIGHT_ALIGN+] Right justified, ragged left. - # |A paragraph that is| - # | right aligned.| - # [+RIGHT_FILL+] Left justified, right ragged, filled to width by - # spaces. (Essentially the same as +LEFT_ALIGN+ except - # that lines are padded on the right.) - # |A paragraph that is| - # |left aligned. | - # [+JUSTIFY+] Fully justified, words filled to width by spaces, - # except the last line. - # |A paragraph that| - # |is justified.| - # - # *Default*:: Text::Format::LEFT_ALIGN - # Used in:: #format, #paragraphs - attr_reader :format_style - - # Specifies the format style. Allowable values are: - # [+LEFT_ALIGN+] Left justified, ragged right. - # |A paragraph that is| - # |left aligned.| - # [+RIGHT_ALIGN+] Right justified, ragged left. - # |A paragraph that is| - # | right aligned.| - # [+RIGHT_FILL+] Left justified, right ragged, filled to width by - # spaces. (Essentially the same as +LEFT_ALIGN+ except - # that lines are padded on the right.) - # |A paragraph that is| - # |left aligned. | - # [+JUSTIFY+] Fully justified, words filled to width by spaces. - # |A paragraph that| - # |is justified.| - # - # *Default*:: Text::Format::LEFT_ALIGN - # Used in:: #format, #paragraphs - def format_style=(fs) - raise ArgumentError, "Invalid value provided for format_style." if ((fs < LEFT_ALIGN) || (fs > JUSTIFY)) - @format_style = fs - end - - # Indicates that the format style is left alignment. - # - # *Default*:: +true+ - # Used in:: #format, #paragraphs - def left_align? - return @format_style == LEFT_ALIGN - end - - # Indicates that the format style is right alignment. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def right_align? - return @format_style == RIGHT_ALIGN - end - - # Indicates that the format style is right fill. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def right_fill? - return @format_style == RIGHT_FILL - end - - # Indicates that the format style is full justification. - # - # *Default*:: +false+ - # Used in:: #format, #paragraphs - def justify? - return @format_style == JUSTIFY - end - - # The default implementation of #hyphenate_to implements - # SPLIT_CONTINUATION. - def hyphenate_to(word, size) - [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]] - end - - private - def __do_split_word(word, size) #:nodoc: - [word[0 .. (size - 1)], word[size .. -1]] - end - - def __format(to_wrap) #:nodoc: - words = to_wrap.split(/\s+/).compact - words.shift if words[0].nil? or words[0].empty? - to_wrap = [] - - abbrev = false - width = @columns - @first_indent - @left_margin - @right_margin - indent_str = ' ' * @first_indent - first_line = true - line = words.shift - abbrev = __is_abbrev(line) unless line.nil? || line.empty? - - while w = words.shift - if (w.size + line.size < (width - 1)) || - ((line !~ LEQ_RE || abbrev) && (w.size + line.size < width)) - line << " " if (line =~ LEQ_RE) && (not abbrev) - line << " #{w}" - else - line, w = __do_break(line, w) if @nobreak - line, w = __do_hyphenate(line, w, width) if @hard_margins - if w.index(/\s+/) - w, *w2 = w.split(/\s+/) - words.unshift(w2) - words.flatten! - end - to_wrap << __make_line(line, indent_str, width, w.nil?) unless line.nil? - if first_line - first_line = false - width = @columns - @body_indent - @left_margin - @right_margin - indent_str = ' ' * @body_indent - end - line = w - end - - abbrev = __is_abbrev(w) unless w.nil? - end - - loop do - break if line.nil? or line.empty? - line, w = __do_hyphenate(line, w, width) if @hard_margins - to_wrap << __make_line(line, indent_str, width, w.nil?) - line = w - end - - if (@tag_paragraph && (to_wrap.size > 0)) then - clr = %r{`(\w+)'}.match([caller(1)].flatten[0])[1] - clr = "" if clr.nil? - - if ((not @tag_text[0].nil?) && (@tag_cur.size < 1) && - (clr != "__paragraphs")) then - @tag_cur = @tag_text[0] - end - - fchar = /(\S)/.match(to_wrap[0])[1] - white = to_wrap[0].index(fchar) - if ((white - @left_margin - 1) > @tag_cur.size) then - white = @tag_cur.size + @left_margin - to_wrap[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}") - else - to_wrap.unshift("#{' ' * @left_margin}#{@tag_cur}\n") - end - end - to_wrap.join('') - end - - # format lines in text into paragraphs with each element of @wrap a - # paragraph; uses Text::Format.format for the formatting - def __paragraphs(to_wrap) #:nodoc: - if ((@first_indent == @body_indent) || @tag_paragraph) then - p_end = "\n" - else - p_end = '' - end - - cnt = 0 - ret = [] - to_wrap.each do |tw| - @tag_cur = @tag_text[cnt] if @tag_paragraph - @tag_cur = '' if @tag_cur.nil? - line = __format(tw) - ret << "#{line}#{p_end}" if (not line.nil?) && (line.size > 0) - cnt += 1 - end - - ret[-1].chomp! unless ret.empty? - ret.join('') - end - - # center text using spaces on left side to pad it out empty lines - # are preserved - def __center(to_center) #:nodoc: - tabs = 0 - width = @columns - @left_margin - @right_margin - centered = [] - to_center.each do |tc| - s = tc.strip - tabs = s.count("\t") - tabs = 0 if tabs.nil? - ct = ((width - s.size - (tabs * @tabstop) + tabs) / 2) - ct = (width - @left_margin - @right_margin) - ct - centered << "#{s.rjust(ct)}\n" - end - centered.join('') - end - - # expand tabs to spaces should be similar to Text::Tabs::expand - def __expand(to_expand) #:nodoc: - expanded = [] - to_expand.split("\n").each { |te| expanded << te.gsub(/\t/, ' ' * @tabstop) } - expanded.join('') - end - - def __unexpand(to_unexpand) #:nodoc: - unexpanded = [] - to_unexpand.split("\n").each { |tu| unexpanded << tu.gsub(/ {#{@tabstop}}/, "\t") } - unexpanded.join('') - end - - def __is_abbrev(word) #:nodoc: - # remove period if there is one. - w = word.gsub(/\.$/, '') unless word.nil? - return true if (!@extra_space || ABBREV.include?(w) || @abbreviations.include?(w)) - false - end - - def __make_line(line, indent, width, last = false) #:nodoc: - lmargin = " " * @left_margin - fill = " " * (width - line.size) if right_fill? && (line.size <= width) - - if (justify? && ((not line.nil?) && (not line.empty?)) && line =~ /\S+\s+\S+/ && !last) - spaces = width - line.size - words = line.split(/(\s+)/) - ws = spaces / (words.size / 2) - spaces = spaces % (words.size / 2) if ws > 0 - words.reverse.each do |rw| - next if (rw =~ /^\S/) - rw.sub!(/^/, " " * ws) - next unless (spaces > 0) - rw.sub!(/^/, " ") - spaces -= 1 - end - line = words.join('') - end - line = "#{lmargin}#{indent}#{line}#{fill}\n" unless line.nil? - if right_align? && (not line.nil?) - line.sub(/^/, " " * (@columns - @right_margin - (line.size - 1))) - else - line - end - end - - def __do_hyphenate(line, next_line, width) #:nodoc: - rline = line.dup rescue line - rnext = next_line.dup rescue next_line - loop do - if rline.size == width - break - elsif rline.size > width - words = rline.strip.split(/\s+/) - word = words[-1].dup - size = width - rline.size + word.size - if (size <= 0) - words[-1] = nil - rline = words.join(' ').strip - rnext = "#{word} #{rnext}".strip - next - end - - first = rest = nil - - if ((@split_rules & SPLIT_HYPHENATION) != 0) - if @hyphenator_arity == 2 - first, rest = @hyphenator.hyphenate_to(word, size) - else - first, rest = @hyphenator.hyphenate_to(word, size, self) - end - end - - if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? - first, rest = self.hyphenate_to(word, size) - end - - if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? - first.nil? or @split_rules == SPLIT_FIXED - first, rest = __do_split_word(word, size) - end - - if first.nil? - words[-1] = nil - rest = word - else - words[-1] = first - @split_words << SplitWord.new(word, first, rest) - end - rline = words.join(' ').strip - rnext = "#{rest} #{rnext}".strip - break - else - break if rnext.nil? or rnext.empty? or rline.nil? or rline.empty? - words = rnext.split(/\s+/) - word = words.shift - size = width - rline.size - 1 - - if (size <= 0) - rnext = "#{word} #{words.join(' ')}".strip - break - end - - first = rest = nil - - if ((@split_rules & SPLIT_HYPHENATION) != 0) - if @hyphenator_arity == 2 - first, rest = @hyphenator.hyphenate_to(word, size) - else - first, rest = @hyphenator.hyphenate_to(word, size, self) - end - end - - first, rest = self.hyphenate_to(word, size) if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? - - first, rest = __do_split_word(word, size) if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? - - if (rline.size + (first ? first.size : 0)) < width - @split_words << SplitWord.new(word, first, rest) - rline = "#{rline} #{first}".strip - rnext = "#{rest} #{words.join(' ')}".strip - end - break - end - end - [rline, rnext] - end - - def __do_break(line, next_line) #:nodoc: - no_brk = false - words = [] - words = line.split(/\s+/) unless line.nil? - last_word = words[-1] - - @nobreak_regex.each { |k, v| no_brk = ((last_word =~ /#{k}/) and (next_line =~ /#{v}/)) } - - if no_brk && words.size > 1 - i = words.size - while i > 0 - no_brk = false - @nobreak_regex.each { |k, v| no_brk = ((words[i + 1] =~ /#{k}/) && (words[i] =~ /#{v}/)) } - i -= 1 - break if not no_brk - end - if i > 0 - l = brk_re(i).match(line) - line.sub!(brk_re(i), l[1]) - next_line = "#{l[2]} #{next_line}" - line.sub!(/\s+$/, '') - end - end - [line, next_line] - end - - def __create(arg = nil, &block) #:nodoc: - # Format::Text.new(text-to-wrap) - @text = arg unless arg.nil? - # Defaults - @columns = 72 - @tabstop = 8 - @first_indent = 4 - @body_indent = 0 - @format_style = LEFT_ALIGN - @left_margin = 0 - @right_margin = 0 - @extra_space = false - @text = Array.new if @text.nil? - @tag_paragraph = false - @tag_text = Array.new - @tag_cur = "" - @abbreviations = Array.new - @nobreak = false - @nobreak_regex = Hash.new - @split_words = Array.new - @hard_margins = false - @split_rules = SPLIT_FIXED - @hyphenator = self - @hyphenator_arity = self.method(:hyphenate_to).arity - - instance_eval(&block) unless block.nil? - end - - public - # Formats text into a nice paragraph format. The text is separated - # into words and then reassembled a word at a time using the settings - # of this Format object. If a word is larger than the number of - # columns available for formatting, then that word will appear on the - # line by itself. - # - # If +to_wrap+ is +nil+, then the value of #text will be - # worked on. - def format(to_wrap = nil) - to_wrap = @text if to_wrap.nil? - if to_wrap.class == Array - __format(to_wrap[0]) - else - __format(to_wrap) - end - end - - # Considers each element of text (provided or internal) as a paragraph. - # If #first_indent is the same as #body_indent, then - # paragraphs will be separated by a single empty line in the result; - # otherwise, the paragraphs will follow immediately after each other. - # Uses #format to do the heavy lifting. - def paragraphs(to_wrap = nil) - to_wrap = @text if to_wrap.nil? - __paragraphs([to_wrap].flatten) - end - - # Centers the text, preserving empty lines and tabs. - def center(to_center = nil) - to_center = @text if to_center.nil? - __center([to_center].flatten) - end - - # Replaces all tab characters in the text with #tabstop spaces. - def expand(to_expand = nil) - to_expand = @text if to_expand.nil? - if to_expand.class == Array - to_expand.collect { |te| __expand(te) } - else - __expand(to_expand) - end - end - - # Replaces all occurrences of #tabstop consecutive spaces - # with a tab character. - def unexpand(to_unexpand = nil) - to_unexpand = @text if to_unexpand.nil? - if to_unexpand.class == Array - to_unexpand.collect { |te| v << __unexpand(te) } - else - __unexpand(to_unexpand) - end - end - - # This constructor takes advantage of a technique for Ruby object - # construction introduced by Andy Hunt and Dave Thomas (see reference), - # where optional values are set using commands in a block. - # - # Text::Format.new { - # columns = 72 - # left_margin = 0 - # right_margin = 0 - # first_indent = 4 - # body_indent = 0 - # format_style = Text::Format::LEFT_ALIGN - # extra_space = false - # abbreviations = {} - # tag_paragraph = false - # tag_text = [] - # nobreak = false - # nobreak_regex = {} - # tabstop = 8 - # text = nil - # } - # - # As shown above, +arg+ is optional. If +arg+ is specified and is a - # +String+, then arg is used as the default value of #text. - # Alternately, an existing Text::Format object can be used or a Hash can - # be used. With all forms, a block can be specified. - # - # *Reference*:: "Object Construction and Blocks" - # - # - def initialize(arg = nil, &block) - case arg - when Text::Format - __create(arg.text) do - @columns = arg.columns - @tabstop = arg.tabstop - @first_indent = arg.first_indent - @body_indent = arg.body_indent - @format_style = arg.format_style - @left_margin = arg.left_margin - @right_margin = arg.right_margin - @extra_space = arg.extra_space - @tag_paragraph = arg.tag_paragraph - @tag_text = arg.tag_text - @abbreviations = arg.abbreviations - @nobreak = arg.nobreak - @nobreak_regex = arg.nobreak_regex - @text = arg.text - @hard_margins = arg.hard_margins - @split_words = arg.split_words - @split_rules = arg.split_rules - @hyphenator = arg.hyphenator - end - instance_eval(&block) unless block.nil? - when Hash - __create do - @columns = arg[:columns] || arg['columns'] || @columns - @tabstop = arg[:tabstop] || arg['tabstop'] || @tabstop - @first_indent = arg[:first_indent] || arg['first_indent'] || @first_indent - @body_indent = arg[:body_indent] || arg['body_indent'] || @body_indent - @format_style = arg[:format_style] || arg['format_style'] || @format_style - @left_margin = arg[:left_margin] || arg['left_margin'] || @left_margin - @right_margin = arg[:right_margin] || arg['right_margin'] || @right_margin - @extra_space = arg[:extra_space] || arg['extra_space'] || @extra_space - @text = arg[:text] || arg['text'] || @text - @tag_paragraph = arg[:tag_paragraph] || arg['tag_paragraph'] || @tag_paragraph - @tag_text = arg[:tag_text] || arg['tag_text'] || @tag_text - @abbreviations = arg[:abbreviations] || arg['abbreviations'] || @abbreviations - @nobreak = arg[:nobreak] || arg['nobreak'] || @nobreak - @nobreak_regex = arg[:nobreak_regex] || arg['nobreak_regex'] || @nobreak_regex - @hard_margins = arg[:hard_margins] || arg['hard_margins'] || @hard_margins - @split_rules = arg[:split_rules] || arg['split_rules'] || @split_rules - @hyphenator = arg[:hyphenator] || arg['hyphenator'] || @hyphenator - end - instance_eval(&block) unless block.nil? - when String - __create(arg, &block) - when NilClass - __create(&block) - else - raise TypeError - end - end - end -end - -if __FILE__ == $0 - require 'test/unit' - - class TestText__Format < Test::Unit::TestCase #:nodoc: - attr_accessor :format_o - - GETTYSBURG = <<-'EOS' - Four score and seven years ago our fathers brought forth on this - continent a new nation, conceived in liberty and dedicated to the - proposition that all men are created equal. Now we are engaged in - a great civil war, testing whether that nation or any nation so - conceived and so dedicated can long endure. We are met on a great - battlefield of that war. We have come to dedicate a portion of - that field as a final resting-place for those who here gave their - lives that that nation might live. It is altogether fitting and - proper that we should do this. But in a larger sense, we cannot - dedicate, we cannot consecrate, we cannot hallow this ground. - The brave men, living and dead who struggled here have consecrated - it far above our poor power to add or detract. The world will - little note nor long remember what we say here, but it can never - forget what they did here. It is for us the living rather to be - dedicated here to the unfinished work which they who fought here - have thus far so nobly advanced. It is rather for us to be here - dedicated to the great task remaining before us--that from these - honored dead we take increased devotion to that cause for which - they gave the last full measure of devotion--that we here highly - resolve that these dead shall not have died in vain, that this - nation under God shall have a new birth of freedom, and that - government of the people, by the people, for the people shall - not perish from the earth. - - -- Pres. Abraham Lincoln, 19 November 1863 - EOS - - 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" - - 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" - - # Tests both abbreviations and abbreviations= - def test_abbreviations - abbr = [" Pres. Abraham Lincoln\n", " Pres. Abraham Lincoln\n"] - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.abbreviations) - assert_nothing_raised { @format_o.abbreviations = [ 'foo', 'bar' ] } - assert_equal([ 'foo', 'bar' ], @format_o.abbreviations) - assert_equal(abbr[0], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.extra_space = true } - assert_equal(abbr[1], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.abbreviations = [ "Pres" ] } - assert_equal([ "Pres" ], @format_o.abbreviations) - assert_equal(abbr[0], @format_o.format(abbr[0])) - assert_nothing_raised { @format_o.extra_space = false } - assert_equal(abbr[0], @format_o.format(abbr[0])) - end - - # Tests both body_indent and body_indent= - def test_body_indent - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = 7 } - assert_equal(7, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = -3 } - assert_equal(3, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = "9" } - assert_equal(9, @format_o.body_indent) - assert_nothing_raised { @format_o.body_indent = "-2" } - assert_equal(2, @format_o.body_indent) - assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[1]) - end - - # Tests both columns and columns= - def test_columns - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(72, @format_o.columns) - assert_nothing_raised { @format_o.columns = 7 } - assert_equal(7, @format_o.columns) - assert_nothing_raised { @format_o.columns = -3 } - assert_equal(3, @format_o.columns) - assert_nothing_raised { @format_o.columns = "9" } - assert_equal(9, @format_o.columns) - assert_nothing_raised { @format_o.columns = "-2" } - assert_equal(2, @format_o.columns) - assert_nothing_raised { @format_o.columns = 40 } - assert_equal(40, @format_o.columns) - assert_match(/this continent$/, - @format_o.format(GETTYSBURG).split("\n")[1]) - end - - # Tests both extra_space and extra_space= - def test_extra_space - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.extra_space) - assert_nothing_raised { @format_o.extra_space = true } - assert(@format_o.extra_space) - # The behaviour of extra_space is tested in test_abbreviations. There - # is no need to reproduce it here. - end - - # Tests both first_indent and first_indent= - def test_first_indent - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(4, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = 7 } - assert_equal(7, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = -3 } - assert_equal(3, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = "9" } - assert_equal(9, @format_o.first_indent) - assert_nothing_raised { @format_o.first_indent = "-2" } - assert_equal(2, @format_o.first_indent) - assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[0]) - end - - def test_format_style - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(Text::Format::LEFT_ALIGN, @format_o.format_style) - assert_match(/^November 1863$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert_equal(Text::Format::RIGHT_ALIGN, @format_o.format_style) - assert_match(/^ +November 1863$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert_equal(Text::Format::RIGHT_FILL, @format_o.format_style) - assert_match(/^November 1863 +$/, - @format_o.format(GETTYSBURG).split("\n")[-1]) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert_equal(Text::Format::JUSTIFY, @format_o.format_style) - assert_match(/^of freedom, and that government of the people, by the people, for the$/, - @format_o.format(GETTYSBURG).split("\n")[-3]) - assert_raise(ArgumentError) { @format_o.format_style = 33 } - end - - def test_tag_paragraph - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.tag_paragraph) - assert_nothing_raised { @format_o.tag_paragraph = true } - assert(@format_o.tag_paragraph) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) - end - - def test_tag_text - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.tag_text) - assert_equal(@format_o.format(GETTYSBURG), - Text::Format.new.format(GETTYSBURG)) - assert_nothing_raised { - @format_o.tag_paragraph = true - @format_o.tag_text = ["Gettysburg Address", "---"] - } - assert_not_equal(@format_o.format(GETTYSBURG), - Text::Format.new.format(GETTYSBURG)) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) - assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG, - GETTYSBURG]), - Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG, - GETTYSBURG])) - end - - def test_justify? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.justify?) - assert_nothing_raised { - @format_o.format_style = Text::Format::JUSTIFY - } - assert(@format_o.justify?) - # The format testing is done in test_format_style - end - - def test_left_align? - assert_nothing_raised { @format_o = Text::Format.new } - assert(@format_o.left_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.left_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.left_align?) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert(!@format_o.left_align?) - # The format testing is done in test_format_style - end - - def test_left_margin - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = -3 } - assert_equal(3, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = "9" } - assert_equal(9, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = "-2" } - assert_equal(2, @format_o.left_margin) - assert_nothing_raised { @format_o.left_margin = 7 } - assert_equal(7, @format_o.left_margin) - assert_nothing_raised { - ft = @format_o.format(GETTYSBURG).split("\n") - assert_match(/^ {11}Four score/, ft[0]) - assert_match(/^ {7}November/, ft[-1]) - } - end - - def test_hard_margins - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.hard_margins) - assert_nothing_raised { - @format_o.hard_margins = true - @format_o.columns = 5 - @format_o.first_indent = 0 - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(@format_o.hard_margins) - assert_equal(FIVE_COL, @format_o.format(GETTYSBURG)) - assert_nothing_raised { - @format_o.split_rules |= Text::Format::SPLIT_CONTINUATION - assert_equal(Text::Format::SPLIT_CONTINUATION_FIXED, - @format_o.split_rules) - } - assert_equal(FIVE_CNT, @format_o.format(GETTYSBURG)) - end - - # Tests both nobreak and nobreak_regex, since one is only useful - # with the other. - def test_nobreak - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.nobreak) - assert(@format_o.nobreak_regex.empty?) - assert_nothing_raised { - @format_o.nobreak = true - @format_o.nobreak_regex = { '^this$' => '^continent$' } - @format_o.columns = 77 - } - assert(@format_o.nobreak) - assert_equal({ '^this$' => '^continent$' }, @format_o.nobreak_regex) - assert_match(/^this continent/, - @format_o.format(GETTYSBURG).split("\n")[1]) - end - - def test_right_align? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.right_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(@format_o.right_align?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(!@format_o.right_align?) - assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } - assert(!@format_o.right_align?) - # The format testing is done in test_format_style - end - - def test_right_fill? - assert_nothing_raised { @format_o = Text::Format.new } - assert(!@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_ALIGN - } - assert(!@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::RIGHT_FILL - } - assert(@format_o.right_fill?) - assert_nothing_raised { - @format_o.format_style = Text::Format::JUSTIFY - } - assert(!@format_o.right_fill?) - # The format testing is done in test_format_style - end - - def test_right_margin - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(0, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = -3 } - assert_equal(3, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = "9" } - assert_equal(9, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = "-2" } - assert_equal(2, @format_o.right_margin) - assert_nothing_raised { @format_o.right_margin = 7 } - assert_equal(7, @format_o.right_margin) - assert_nothing_raised { - ft = @format_o.format(GETTYSBURG).split("\n") - assert_match(/^ {4}Four score.*forth on$/, ft[0]) - assert_match(/^November/, ft[-1]) - } - end - - def test_tabstop - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(8, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = 7 } - assert_equal(7, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = -3 } - assert_equal(3, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = "9" } - assert_equal(9, @format_o.tabstop) - assert_nothing_raised { @format_o.tabstop = "-2" } - assert_equal(2, @format_o.tabstop) - end - - def test_text - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal([], @format_o.text) - assert_nothing_raised { @format_o.text = "Test Text" } - assert_equal("Test Text", @format_o.text) - assert_nothing_raised { @format_o.text = ["Line 1", "Line 2"] } - assert_equal(["Line 1", "Line 2"], @format_o.text) - end - - def test_s_new - # new(NilClass) { block } - assert_nothing_raised do - @format_o = Text::Format.new { - self.text = "Test 1, 2, 3" - } - end - assert_equal("Test 1, 2, 3", @format_o.text) - - # new(Hash Symbols) - assert_nothing_raised { @format_o = Text::Format.new(:columns => 72) } - assert_equal(72, @format_o.columns) - - # new(Hash String) - assert_nothing_raised { @format_o = Text::Format.new('columns' => 72) } - assert_equal(72, @format_o.columns) - - # new(Hash) { block } - assert_nothing_raised do - @format_o = Text::Format.new('columns' => 80) { - self.text = "Test 4, 5, 6" - } - end - assert_equal("Test 4, 5, 6", @format_o.text) - assert_equal(80, @format_o.columns) - - # new(Text::Format) - assert_nothing_raised do - fo = Text::Format.new(@format_o) - assert(fo == @format_o) - end - - # new(Text::Format) { block } - assert_nothing_raised do - fo = Text::Format.new(@format_o) { self.columns = 79 } - assert(fo != @format_o) - end - - # new(String) - assert_nothing_raised { @format_o = Text::Format.new("Test A, B, C") } - assert_equal("Test A, B, C", @format_o.text) - - # new(String) { block } - assert_nothing_raised do - @format_o = Text::Format.new("Test X, Y, Z") { self.columns = -5 } - end - assert_equal("Test X, Y, Z", @format_o.text) - assert_equal(5, @format_o.columns) - end - - def test_center - assert_nothing_raised { @format_o = Text::Format.new } - assert_nothing_raised do - ct = @format_o.center(GETTYSBURG.split("\n")).split("\n") - assert_match(/^ Four score and seven years ago our fathers brought forth on this/, ct[0]) - assert_match(/^ not perish from the earth./, ct[-3]) - end - end - - def test_expand - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal(" ", @format_o.expand("\t ")) - assert_nothing_raised { @format_o.tabstop = 4 } - assert_equal(" ", @format_o.expand("\t ")) - end - - def test_unexpand - assert_nothing_raised { @format_o = Text::Format.new } - assert_equal("\t ", @format_o.unexpand(" ")) - assert_nothing_raised { @format_o.tabstop = 4 } - assert_equal("\t ", @format_o.unexpand(" ")) - end - - def test_space_only - assert_equal("", Text::Format.new.format(" ")) - assert_equal("", Text::Format.new.format("\n")) - assert_equal("", Text::Format.new.format(" ")) - assert_equal("", Text::Format.new.format(" \n")) - assert_equal("", Text::Format.new.paragraphs("\n")) - assert_equal("", Text::Format.new.paragraphs(" ")) - assert_equal("", Text::Format.new.paragraphs(" ")) - assert_equal("", Text::Format.new.paragraphs(" \n")) - assert_equal("", Text::Format.new.paragraphs(["\n"])) - assert_equal("", Text::Format.new.paragraphs([" "])) - assert_equal("", Text::Format.new.paragraphs([" "])) - assert_equal("", Text::Format.new.paragraphs([" \n"])) - end - - def test_splendiferous - h = nil - test = "This is a splendiferous test" - assert_nothing_raised { @format_o = Text::Format.new(:columns => 6, :left_margin => 0, :indent => 0, :first_indent => 0) } - assert_match(/^splendiferous$/, @format_o.format(test)) - assert_nothing_raised { @format_o.hard_margins = true } - assert_match(/^lendif$/, @format_o.format(test)) - assert_nothing_raised { h = Object.new } - assert_nothing_raised do - @format_o.split_rules = Text::Format::SPLIT_HYPHENATION - class << h #:nodoc: - def hyphenate_to(word, size) - return ["", word] if size < 2 - [word[0 ... size], word[size .. -1]] - end - end - @format_o.hyphenator = h - end - assert_match(/^iferou$/, @format_o.format(test)) - assert_nothing_raised { h = Object.new } - assert_nothing_raised do - class << h #:nodoc: - def hyphenate_to(word, size, formatter) - return ["", word] if word.size < formatter.columns - [word[0 ... size], word[size .. -1]] - end - end - @format_o.hyphenator = h - end - assert_match(/^ferous$/, @format_o.format(test)) - end - end -end +#-- +# Text::Format for Ruby +# Version 0.63 +# +# Copyright (c) 2002 - 2003 Austin Ziegler +# +# $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $ +# +# ========================================================================== +# Revision History :: +# YYYY.MM.DD Change ID Developer +# Description +# -------------------------------------------------------------------------- +# 2002.10.18 Austin Ziegler +# Fixed a minor problem with tabs not being counted. Changed +# abbreviations from Hash to Array to better suit Ruby's +# capabilities. Fixed problems with the way that Array arguments +# are handled in calls to the major object types, excepting in +# Text::Format#expand and Text::Format#unexpand (these will +# probably need to be fixed). +# 2002.10.30 Austin Ziegler +# Fixed the ordering of the <=> for binary tests. Fixed +# Text::Format#expand and Text::Format#unexpand to handle array +# arguments better. +# 2003.01.24 Austin Ziegler +# Fixed a problem with Text::Format::RIGHT_FILL handling where a +# single word is larger than #columns. Removed Comparable +# capabilities (<=> doesn't make sense; == does). Added Symbol +# equivalents for the Hash initialization. Hash initialization has +# been modified so that values are set as follows (Symbols are +# highest priority; strings are middle; defaults are lowest): +# @columns = arg[:columns] || arg['columns'] || @columns +# Added #hard_margins, #split_rules, #hyphenator, and #split_words. +# 2003.02.07 Austin Ziegler +# Fixed the installer for proper case-sensitive handling. +# 2003.03.28 Austin Ziegler +# Added the ability for a hyphenator to receive the formatter +# object. Fixed a bug for strings matching /\A\s*\Z/ failing +# entirely. Fixed a test case failing under 1.6.8. +# 2003.04.04 Austin Ziegler +# Handle the case of hyphenators returning nil for first/rest. +# 2003.09.17 Austin Ziegler +# Fixed a problem where #paragraphs(" ") was raising +# NoMethodError. +# +# ========================================================================== +#++ + +module Text #:nodoc: + # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It + # is available under Ruby's licence, the Perl Artistic licence, or the + # GNU GPL version 2 (or at your option, any later version). As a + # special exception, for use with official Rails (provided by the + # rubyonrails.org development team) and any project created with + # official Rails, the following alternative MIT-style licence may be + # used: + # + # == Text::Format Licence for Rails and Rails Applications + # Permission is hereby granted, free of charge, to any person + # obtaining a copy of this software and associated documentation files + # (the "Software"), to deal in the Software without restriction, + # including without limitation the rights to use, copy, modify, merge, + # publish, distribute, sublicense, and/or sell copies of the Software, + # and to permit persons to whom the Software is furnished to do so, + # subject to the following conditions: + # + # * The names of its contributors may not be used to endorse or + # promote products derived from this software without specific prior + # written permission. + # + # The above copyright notice and this permission notice shall be + # included in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + # SOFTWARE. + class Format + VERSION = '0.63' + + # Local abbreviations. More can be added with Text::Format.abbreviations + ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ] + + # Formatting values + LEFT_ALIGN = 0 + RIGHT_ALIGN = 1 + RIGHT_FILL = 2 + JUSTIFY = 3 + + # Word split modes (only applies when #hard_margins is true). + SPLIT_FIXED = 1 + SPLIT_CONTINUATION = 2 + SPLIT_HYPHENATION = 4 + SPLIT_CONTINUATION_FIXED = SPLIT_CONTINUATION | SPLIT_FIXED + SPLIT_HYPHENATION_FIXED = SPLIT_HYPHENATION | SPLIT_FIXED + SPLIT_HYPHENATION_CONTINUATION = SPLIT_HYPHENATION | SPLIT_CONTINUATION + SPLIT_ALL = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED + + # Words forcibly split by Text::Format will be stored as split words. + # This class represents a word forcibly split. + class SplitWord + # The word that was split. + attr_reader :word + # The first part of the word that was split. + attr_reader :first + # The remainder of the word that was split. + attr_reader :rest + + def initialize(word, first, rest) #:nodoc: + @word = word + @first = first + @rest = rest + end + end + + private + LEQ_RE = /[.?!]['"]?$/ + + def brk_re(i) #:nodoc: + %r/((?:\S+\s+){#{i}})(.+)/ + end + + def posint(p) #:nodoc: + p.to_i.abs + end + + public + # Compares two Text::Format objects. All settings of the objects are + # compared *except* #hyphenator. Generated results (e.g., #split_words) + # are not compared, either. + def ==(o) + (@text == o.text) && + (@columns == o.columns) && + (@left_margin == o.left_margin) && + (@right_margin == o.right_margin) && + (@hard_margins == o.hard_margins) && + (@split_rules == o.split_rules) && + (@first_indent == o.first_indent) && + (@body_indent == o.body_indent) && + (@tag_text == o.tag_text) && + (@tabstop == o.tabstop) && + (@format_style == o.format_style) && + (@extra_space == o.extra_space) && + (@tag_paragraph == o.tag_paragraph) && + (@nobreak == o.nobreak) && + (@abbreviations == o.abbreviations) && + (@nobreak_regex == o.nobreak_regex) + end + + # The text to be manipulated. Note that value is optional, but if the + # formatting functions are called without values, this text is what will + # be formatted. + # + # *Default*:: [] + # Used in:: All methods + attr_accessor :text + + # The total width of the format area. The margins, indentation, and text + # are formatted into this space. + # + # COLUMNS + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here right margin + # + # *Default*:: 72 + # Used in:: #format, #paragraphs, + # #center + attr_reader :columns + + # The total width of the format area. The margins, indentation, and text + # are formatted into this space. The value provided is silently + # converted to a positive integer. + # + # COLUMNS + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here right margin + # + # *Default*:: 72 + # Used in:: #format, #paragraphs, + # #center + def columns=(c) + @columns = posint(c) + end + + # The number of spaces used for the left margin. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # LEFT MARGIN indent text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + attr_reader :left_margin + + # The number of spaces used for the left margin. The value provided is + # silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # LEFT MARGIN indent text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + def left_margin=(left) + @left_margin = posint(left) + end + + # The number of spaces used for the right margin. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here RIGHT MARGIN + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + attr_reader :right_margin + + # The number of spaces used for the right margin. The value provided is + # silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin indent text is formatted into here RIGHT MARGIN + # + # *Default*:: 0 + # Used in:: #format, #paragraphs, + # #center + def right_margin=(r) + @right_margin = posint(r) + end + + # The number of spaces to indent the first line of a paragraph. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 4 + # Used in:: #format, #paragraphs + attr_reader :first_indent + + # The number of spaces to indent the first line of a paragraph. The + # value provided is silently converted to a positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 4 + # Used in:: #format, #paragraphs + def first_indent=(f) + @first_indent = posint(f) + end + + # The number of spaces to indent all lines after the first line of a + # paragraph. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs + attr_reader :body_indent + + # The number of spaces to indent all lines after the first line of + # a paragraph. The value provided is silently converted to a + # positive integer value. + # + # columns + # <--------------------------------------------------------------> + # <-----------><------><---------------------------><------------> + # left margin INDENT text is formatted into here right margin + # + # *Default*:: 0 + # Used in:: #format, #paragraphs + def body_indent=(b) + @body_indent = posint(b) + end + + # Normally, words larger than the format area will be placed on a line + # by themselves. Setting this to +true+ will force words larger than the + # format area to be split into one or more "words" each at most the size + # of the format area. The first line and the original word will be + # placed into #split_words. Note that this will cause the + # output to look *similar* to a #format_style of JUSTIFY. (Lines will be + # filled as much as possible.) + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :hard_margins + + # An array of words split during formatting if #hard_margins is set to + # +true+. + # #split_words << Text::Format::SplitWord.new(word, first, rest) + attr_reader :split_words + + # The object responsible for hyphenating. It must respond to + # #hyphenate_to(word, size) or #hyphenate_to(word, size, formatter) and + # return an array of the word split into two parts; if there is a + # hyphenation mark to be applied, responsibility belongs to the + # hyphenator object. The size is the MAXIMUM size permitted, including + # any hyphenation marks. If the #hyphenate_to method has an arity of 3, + # the formatter will be provided to the method. This allows the + # hyphenator to make decisions about the hyphenation based on the + # formatting rules. + # + # *Default*:: +nil+ + # Used in:: #format, #paragraphs + attr_reader :hyphenator + + # The object responsible for hyphenating. It must respond to + # #hyphenate_to(word, size) and return an array of the word hyphenated + # into two parts. The size is the MAXIMUM size permitted, including any + # hyphenation marks. + # + # *Default*:: +nil+ + # Used in:: #format, #paragraphs + def hyphenator=(h) + raise ArgumentError, "#{h.inspect} is not a valid hyphenator." unless h.respond_to?(:hyphenate_to) + arity = h.method(:hyphenate_to).arity + raise ArgumentError, "#{h.inspect} must have exactly two or three arguments." unless [2, 3].include?(arity) + @hyphenator = h + @hyphenator_arity = arity + end + + # Specifies the split mode; used only when #hard_margins is set to + # +true+. Allowable values are: + # [+SPLIT_FIXED+] The word will be split at the number of + # characters needed, with no marking at all. + # repre + # senta + # ion + # [+SPLIT_CONTINUATION+] The word will be split at the number of + # characters needed, with a C-style continuation + # character. If a word is the only item on a + # line and it cannot be split into an + # appropriate size, SPLIT_FIXED will be used. + # repr\ + # esen\ + # tati\ + # on + # [+SPLIT_HYPHENATION+] The word will be split according to the + # hyphenator specified in #hyphenator. If there + # is no #hyphenator specified, works like + # SPLIT_CONTINUATION. The example is using + # TeX::Hyphen. If a word is the only item on a + # line and it cannot be split into an + # appropriate size, SPLIT_CONTINUATION mode will + # be used. + # rep- + # re- + # sen- + # ta- + # tion + # + # *Default*:: Text::Format::SPLIT_FIXED + # Used in:: #format, #paragraphs + attr_reader :split_rules + + # Specifies the split mode; used only when #hard_margins is set to + # +true+. Allowable values are: + # [+SPLIT_FIXED+] The word will be split at the number of + # characters needed, with no marking at all. + # repre + # senta + # ion + # [+SPLIT_CONTINUATION+] The word will be split at the number of + # characters needed, with a C-style continuation + # character. + # repr\ + # esen\ + # tati\ + # on + # [+SPLIT_HYPHENATION+] The word will be split according to the + # hyphenator specified in #hyphenator. If there + # is no #hyphenator specified, works like + # SPLIT_CONTINUATION. The example is using + # TeX::Hyphen as the #hyphenator. + # rep- + # re- + # sen- + # ta- + # tion + # + # These values can be bitwise ORed together (e.g., SPLIT_FIXED | + # SPLIT_CONTINUATION) to provide fallback split methods. In the + # example given, an attempt will be made to split the word using the + # rules of SPLIT_CONTINUATION; if there is not enough room, the word + # will be split with the rules of SPLIT_FIXED. These combinations are + # also available as the following values: + # * +SPLIT_CONTINUATION_FIXED+ + # * +SPLIT_HYPHENATION_FIXED+ + # * +SPLIT_HYPHENATION_CONTINUATION+ + # * +SPLIT_ALL+ + # + # *Default*:: Text::Format::SPLIT_FIXED + # Used in:: #format, #paragraphs + def split_rules=(s) + raise ArgumentError, "Invalid value provided for split_rules." if ((s < SPLIT_FIXED) || (s > SPLIT_ALL)) + @split_rules = s + end + + # Indicates whether sentence terminators should be followed by a single + # space (+false+), or two spaces (+true+). + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :extra_space + + # Defines the current abbreviations as an array. This is only used if + # extra_space is turned on. + # + # If one is abbreviating "President" as "Pres." (abbreviations = + # ["Pres"]), then the results of formatting will be as illustrated in + # the table below: + # + # extra_space | include? | !include? + # true | Pres. Lincoln | Pres. Lincoln + # false | Pres. Lincoln | Pres. Lincoln + # + # *Default*:: {} + # Used in:: #format, #paragraphs + attr_accessor :abbreviations + + # Indicates whether the formatting of paragraphs should be done with + # tagged paragraphs. Useful only with #tag_text. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :tag_paragraph + + # The array of text to be placed before each paragraph when + # #tag_paragraph is +true+. When #format() is called, + # only the first element of the array is used. When #paragraphs + # is called, then each entry in the array will be used once, with + # corresponding paragraphs. If the tag elements are exhausted before the + # text is exhausted, then the remaining paragraphs will not be tagged. + # Regardless of indentation settings, a blank line will be inserted + # between all paragraphs when #tag_paragraph is +true+. + # + # *Default*:: [] + # Used in:: #format, #paragraphs + attr_accessor :tag_text + + # Indicates whether or not the non-breaking space feature should be + # used. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + attr_accessor :nobreak + + # A hash which holds the regular expressions on which spaces should not + # be broken. The hash is set up such that the key is the first word and + # the value is the second word. + # + # For example, if +nobreak_regex+ contains the following hash: + # + # { '^Mrs?\.$' => '\S+$', '^\S+$' => '^(?:S|J)r\.$'} + # + # Then "Mr. Jones", "Mrs. Jones", and "Jones Jr." would not be broken. + # If this simple matching algorithm indicates that there should not be a + # break at the current end of line, then a backtrack is done until there + # are two words on which line breaking is permitted. If two such words + # are not found, then the end of the line will be broken *regardless*. + # If there is a single word on the current line, then no backtrack is + # done and the word is stuck on the end. + # + # *Default*:: {} + # Used in:: #format, #paragraphs + attr_accessor :nobreak_regex + + # Indicates the number of spaces that a single tab represents. + # + # *Default*:: 8 + # Used in:: #expand, #unexpand, + # #paragraphs + attr_reader :tabstop + + # Indicates the number of spaces that a single tab represents. + # + # *Default*:: 8 + # Used in:: #expand, #unexpand, + # #paragraphs + def tabstop=(t) + @tabstop = posint(t) + end + + # Specifies the format style. Allowable values are: + # [+LEFT_ALIGN+] Left justified, ragged right. + # |A paragraph that is| + # |left aligned.| + # [+RIGHT_ALIGN+] Right justified, ragged left. + # |A paragraph that is| + # | right aligned.| + # [+RIGHT_FILL+] Left justified, right ragged, filled to width by + # spaces. (Essentially the same as +LEFT_ALIGN+ except + # that lines are padded on the right.) + # |A paragraph that is| + # |left aligned. | + # [+JUSTIFY+] Fully justified, words filled to width by spaces, + # except the last line. + # |A paragraph that| + # |is justified.| + # + # *Default*:: Text::Format::LEFT_ALIGN + # Used in:: #format, #paragraphs + attr_reader :format_style + + # Specifies the format style. Allowable values are: + # [+LEFT_ALIGN+] Left justified, ragged right. + # |A paragraph that is| + # |left aligned.| + # [+RIGHT_ALIGN+] Right justified, ragged left. + # |A paragraph that is| + # | right aligned.| + # [+RIGHT_FILL+] Left justified, right ragged, filled to width by + # spaces. (Essentially the same as +LEFT_ALIGN+ except + # that lines are padded on the right.) + # |A paragraph that is| + # |left aligned. | + # [+JUSTIFY+] Fully justified, words filled to width by spaces. + # |A paragraph that| + # |is justified.| + # + # *Default*:: Text::Format::LEFT_ALIGN + # Used in:: #format, #paragraphs + def format_style=(fs) + raise ArgumentError, "Invalid value provided for format_style." if ((fs < LEFT_ALIGN) || (fs > JUSTIFY)) + @format_style = fs + end + + # Indicates that the format style is left alignment. + # + # *Default*:: +true+ + # Used in:: #format, #paragraphs + def left_align? + return @format_style == LEFT_ALIGN + end + + # Indicates that the format style is right alignment. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def right_align? + return @format_style == RIGHT_ALIGN + end + + # Indicates that the format style is right fill. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def right_fill? + return @format_style == RIGHT_FILL + end + + # Indicates that the format style is full justification. + # + # *Default*:: +false+ + # Used in:: #format, #paragraphs + def justify? + return @format_style == JUSTIFY + end + + # The default implementation of #hyphenate_to implements + # SPLIT_CONTINUATION. + def hyphenate_to(word, size) + [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]] + end + + private + def __do_split_word(word, size) #:nodoc: + [word[0 .. (size - 1)], word[size .. -1]] + end + + def __format(to_wrap) #:nodoc: + words = to_wrap.split(/\s+/).compact + words.shift if words[0].nil? or words[0].empty? + to_wrap = [] + + abbrev = false + width = @columns - @first_indent - @left_margin - @right_margin + indent_str = ' ' * @first_indent + first_line = true + line = words.shift + abbrev = __is_abbrev(line) unless line.nil? || line.empty? + + while w = words.shift + if (w.size + line.size < (width - 1)) || + ((line !~ LEQ_RE || abbrev) && (w.size + line.size < width)) + line << " " if (line =~ LEQ_RE) && (not abbrev) + line << " #{w}" + else + line, w = __do_break(line, w) if @nobreak + line, w = __do_hyphenate(line, w, width) if @hard_margins + if w.index(/\s+/) + w, *w2 = w.split(/\s+/) + words.unshift(w2) + words.flatten! + end + to_wrap << __make_line(line, indent_str, width, w.nil?) unless line.nil? + if first_line + first_line = false + width = @columns - @body_indent - @left_margin - @right_margin + indent_str = ' ' * @body_indent + end + line = w + end + + abbrev = __is_abbrev(w) unless w.nil? + end + + loop do + break if line.nil? or line.empty? + line, w = __do_hyphenate(line, w, width) if @hard_margins + to_wrap << __make_line(line, indent_str, width, w.nil?) + line = w + end + + if (@tag_paragraph && (to_wrap.size > 0)) then + clr = %r{`(\w+)'}.match([caller(1)].flatten[0])[1] + clr = "" if clr.nil? + + if ((not @tag_text[0].nil?) && (@tag_cur.size < 1) && + (clr != "__paragraphs")) then + @tag_cur = @tag_text[0] + end + + fchar = /(\S)/.match(to_wrap[0])[1] + white = to_wrap[0].index(fchar) + if ((white - @left_margin - 1) > @tag_cur.size) then + white = @tag_cur.size + @left_margin + to_wrap[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}") + else + to_wrap.unshift("#{' ' * @left_margin}#{@tag_cur}\n") + end + end + to_wrap.join('') + end + + # format lines in text into paragraphs with each element of @wrap a + # paragraph; uses Text::Format.format for the formatting + def __paragraphs(to_wrap) #:nodoc: + if ((@first_indent == @body_indent) || @tag_paragraph) then + p_end = "\n" + else + p_end = '' + end + + cnt = 0 + ret = [] + to_wrap.each do |tw| + @tag_cur = @tag_text[cnt] if @tag_paragraph + @tag_cur = '' if @tag_cur.nil? + line = __format(tw) + ret << "#{line}#{p_end}" if (not line.nil?) && (line.size > 0) + cnt += 1 + end + + ret[-1].chomp! unless ret.empty? + ret.join('') + end + + # center text using spaces on left side to pad it out empty lines + # are preserved + def __center(to_center) #:nodoc: + tabs = 0 + width = @columns - @left_margin - @right_margin + centered = [] + to_center.each do |tc| + s = tc.strip + tabs = s.count("\t") + tabs = 0 if tabs.nil? + ct = ((width - s.size - (tabs * @tabstop) + tabs) / 2) + ct = (width - @left_margin - @right_margin) - ct + centered << "#{s.rjust(ct)}\n" + end + centered.join('') + end + + # expand tabs to spaces should be similar to Text::Tabs::expand + def __expand(to_expand) #:nodoc: + expanded = [] + to_expand.split("\n").each { |te| expanded << te.gsub(/\t/, ' ' * @tabstop) } + expanded.join('') + end + + def __unexpand(to_unexpand) #:nodoc: + unexpanded = [] + to_unexpand.split("\n").each { |tu| unexpanded << tu.gsub(/ {#{@tabstop}}/, "\t") } + unexpanded.join('') + end + + def __is_abbrev(word) #:nodoc: + # remove period if there is one. + w = word.gsub(/\.$/, '') unless word.nil? + return true if (!@extra_space || ABBREV.include?(w) || @abbreviations.include?(w)) + false + end + + def __make_line(line, indent, width, last = false) #:nodoc: + lmargin = " " * @left_margin + fill = " " * (width - line.size) if right_fill? && (line.size <= width) + + if (justify? && ((not line.nil?) && (not line.empty?)) && line =~ /\S+\s+\S+/ && !last) + spaces = width - line.size + words = line.split(/(\s+)/) + ws = spaces / (words.size / 2) + spaces = spaces % (words.size / 2) if ws > 0 + words.reverse.each do |rw| + next if (rw =~ /^\S/) + rw.sub!(/^/, " " * ws) + next unless (spaces > 0) + rw.sub!(/^/, " ") + spaces -= 1 + end + line = words.join('') + end + line = "#{lmargin}#{indent}#{line}#{fill}\n" unless line.nil? + if right_align? && (not line.nil?) + line.sub(/^/, " " * (@columns - @right_margin - (line.size - 1))) + else + line + end + end + + def __do_hyphenate(line, next_line, width) #:nodoc: + rline = line.dup rescue line + rnext = next_line.dup rescue next_line + loop do + if rline.size == width + break + elsif rline.size > width + words = rline.strip.split(/\s+/) + word = words[-1].dup + size = width - rline.size + word.size + if (size <= 0) + words[-1] = nil + rline = words.join(' ').strip + rnext = "#{word} #{rnext}".strip + next + end + + first = rest = nil + + if ((@split_rules & SPLIT_HYPHENATION) != 0) + if @hyphenator_arity == 2 + first, rest = @hyphenator.hyphenate_to(word, size) + else + first, rest = @hyphenator.hyphenate_to(word, size, self) + end + end + + if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? + first, rest = self.hyphenate_to(word, size) + end + + if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? + first.nil? or @split_rules == SPLIT_FIXED + first, rest = __do_split_word(word, size) + end + + if first.nil? + words[-1] = nil + rest = word + else + words[-1] = first + @split_words << SplitWord.new(word, first, rest) + end + rline = words.join(' ').strip + rnext = "#{rest} #{rnext}".strip + break + else + break if rnext.nil? or rnext.empty? or rline.nil? or rline.empty? + words = rnext.split(/\s+/) + word = words.shift + size = width - rline.size - 1 + + if (size <= 0) + rnext = "#{word} #{words.join(' ')}".strip + break + end + + first = rest = nil + + if ((@split_rules & SPLIT_HYPHENATION) != 0) + if @hyphenator_arity == 2 + first, rest = @hyphenator.hyphenate_to(word, size) + else + first, rest = @hyphenator.hyphenate_to(word, size, self) + end + end + + first, rest = self.hyphenate_to(word, size) if ((@split_rules & SPLIT_CONTINUATION) != 0) and first.nil? + + first, rest = __do_split_word(word, size) if ((@split_rules & SPLIT_FIXED) != 0) and first.nil? + + if (rline.size + (first ? first.size : 0)) < width + @split_words << SplitWord.new(word, first, rest) + rline = "#{rline} #{first}".strip + rnext = "#{rest} #{words.join(' ')}".strip + end + break + end + end + [rline, rnext] + end + + def __do_break(line, next_line) #:nodoc: + no_brk = false + words = [] + words = line.split(/\s+/) unless line.nil? + last_word = words[-1] + + @nobreak_regex.each { |k, v| no_brk = ((last_word =~ /#{k}/) and (next_line =~ /#{v}/)) } + + if no_brk && words.size > 1 + i = words.size + while i > 0 + no_brk = false + @nobreak_regex.each { |k, v| no_brk = ((words[i + 1] =~ /#{k}/) && (words[i] =~ /#{v}/)) } + i -= 1 + break if not no_brk + end + if i > 0 + l = brk_re(i).match(line) + line.sub!(brk_re(i), l[1]) + next_line = "#{l[2]} #{next_line}" + line.sub!(/\s+$/, '') + end + end + [line, next_line] + end + + def __create(arg = nil, &block) #:nodoc: + # Format::Text.new(text-to-wrap) + @text = arg unless arg.nil? + # Defaults + @columns = 72 + @tabstop = 8 + @first_indent = 4 + @body_indent = 0 + @format_style = LEFT_ALIGN + @left_margin = 0 + @right_margin = 0 + @extra_space = false + @text = Array.new if @text.nil? + @tag_paragraph = false + @tag_text = Array.new + @tag_cur = "" + @abbreviations = Array.new + @nobreak = false + @nobreak_regex = Hash.new + @split_words = Array.new + @hard_margins = false + @split_rules = SPLIT_FIXED + @hyphenator = self + @hyphenator_arity = self.method(:hyphenate_to).arity + + instance_eval(&block) unless block.nil? + end + + public + # Formats text into a nice paragraph format. The text is separated + # into words and then reassembled a word at a time using the settings + # of this Format object. If a word is larger than the number of + # columns available for formatting, then that word will appear on the + # line by itself. + # + # If +to_wrap+ is +nil+, then the value of #text will be + # worked on. + def format(to_wrap = nil) + to_wrap = @text if to_wrap.nil? + if to_wrap.class == Array + __format(to_wrap[0]) + else + __format(to_wrap) + end + end + + # Considers each element of text (provided or internal) as a paragraph. + # If #first_indent is the same as #body_indent, then + # paragraphs will be separated by a single empty line in the result; + # otherwise, the paragraphs will follow immediately after each other. + # Uses #format to do the heavy lifting. + def paragraphs(to_wrap = nil) + to_wrap = @text if to_wrap.nil? + __paragraphs([to_wrap].flatten) + end + + # Centers the text, preserving empty lines and tabs. + def center(to_center = nil) + to_center = @text if to_center.nil? + __center([to_center].flatten) + end + + # Replaces all tab characters in the text with #tabstop spaces. + def expand(to_expand = nil) + to_expand = @text if to_expand.nil? + if to_expand.class == Array + to_expand.collect { |te| __expand(te) } + else + __expand(to_expand) + end + end + + # Replaces all occurrences of #tabstop consecutive spaces + # with a tab character. + def unexpand(to_unexpand = nil) + to_unexpand = @text if to_unexpand.nil? + if to_unexpand.class == Array + to_unexpand.collect { |te| v << __unexpand(te) } + else + __unexpand(to_unexpand) + end + end + + # This constructor takes advantage of a technique for Ruby object + # construction introduced by Andy Hunt and Dave Thomas (see reference), + # where optional values are set using commands in a block. + # + # Text::Format.new { + # columns = 72 + # left_margin = 0 + # right_margin = 0 + # first_indent = 4 + # body_indent = 0 + # format_style = Text::Format::LEFT_ALIGN + # extra_space = false + # abbreviations = {} + # tag_paragraph = false + # tag_text = [] + # nobreak = false + # nobreak_regex = {} + # tabstop = 8 + # text = nil + # } + # + # As shown above, +arg+ is optional. If +arg+ is specified and is a + # +String+, then arg is used as the default value of #text. + # Alternately, an existing Text::Format object can be used or a Hash can + # be used. With all forms, a block can be specified. + # + # *Reference*:: "Object Construction and Blocks" + # + # + def initialize(arg = nil, &block) + @text = nil + case arg + when Text::Format + __create(arg.text) do + @columns = arg.columns + @tabstop = arg.tabstop + @first_indent = arg.first_indent + @body_indent = arg.body_indent + @format_style = arg.format_style + @left_margin = arg.left_margin + @right_margin = arg.right_margin + @extra_space = arg.extra_space + @tag_paragraph = arg.tag_paragraph + @tag_text = arg.tag_text + @abbreviations = arg.abbreviations + @nobreak = arg.nobreak + @nobreak_regex = arg.nobreak_regex + @text = arg.text + @hard_margins = arg.hard_margins + @split_words = arg.split_words + @split_rules = arg.split_rules + @hyphenator = arg.hyphenator + end + instance_eval(&block) unless block.nil? + when Hash + __create do + @columns = arg[:columns] || arg['columns'] || @columns + @tabstop = arg[:tabstop] || arg['tabstop'] || @tabstop + @first_indent = arg[:first_indent] || arg['first_indent'] || @first_indent + @body_indent = arg[:body_indent] || arg['body_indent'] || @body_indent + @format_style = arg[:format_style] || arg['format_style'] || @format_style + @left_margin = arg[:left_margin] || arg['left_margin'] || @left_margin + @right_margin = arg[:right_margin] || arg['right_margin'] || @right_margin + @extra_space = arg[:extra_space] || arg['extra_space'] || @extra_space + @text = arg[:text] || arg['text'] || @text + @tag_paragraph = arg[:tag_paragraph] || arg['tag_paragraph'] || @tag_paragraph + @tag_text = arg[:tag_text] || arg['tag_text'] || @tag_text + @abbreviations = arg[:abbreviations] || arg['abbreviations'] || @abbreviations + @nobreak = arg[:nobreak] || arg['nobreak'] || @nobreak + @nobreak_regex = arg[:nobreak_regex] || arg['nobreak_regex'] || @nobreak_regex + @hard_margins = arg[:hard_margins] || arg['hard_margins'] || @hard_margins + @split_rules = arg[:split_rules] || arg['split_rules'] || @split_rules + @hyphenator = arg[:hyphenator] || arg['hyphenator'] || @hyphenator + end + instance_eval(&block) unless block.nil? + when String + __create(arg, &block) + when NilClass + __create(&block) + else + raise TypeError + end + end + end +end + +if __FILE__ == $0 + require 'test/unit' + + class TestText__Format < Test::Unit::TestCase #:nodoc: + attr_accessor :format_o + + GETTYSBURG = <<-'EOS' + Four score and seven years ago our fathers brought forth on this + continent a new nation, conceived in liberty and dedicated to the + proposition that all men are created equal. Now we are engaged in + a great civil war, testing whether that nation or any nation so + conceived and so dedicated can long endure. We are met on a great + battlefield of that war. We have come to dedicate a portion of + that field as a final resting-place for those who here gave their + lives that that nation might live. It is altogether fitting and + proper that we should do this. But in a larger sense, we cannot + dedicate, we cannot consecrate, we cannot hallow this ground. + The brave men, living and dead who struggled here have consecrated + it far above our poor power to add or detract. The world will + little note nor long remember what we say here, but it can never + forget what they did here. It is for us the living rather to be + dedicated here to the unfinished work which they who fought here + have thus far so nobly advanced. It is rather for us to be here + dedicated to the great task remaining before us--that from these + honored dead we take increased devotion to that cause for which + they gave the last full measure of devotion--that we here highly + resolve that these dead shall not have died in vain, that this + nation under God shall have a new birth of freedom, and that + government of the people, by the people, for the people shall + not perish from the earth. + + -- Pres. Abraham Lincoln, 19 November 1863 + EOS + + 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" + + 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" + + # Tests both abbreviations and abbreviations= + def test_abbreviations + abbr = [" Pres. Abraham Lincoln\n", " Pres. Abraham Lincoln\n"] + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.abbreviations) + assert_nothing_raised { @format_o.abbreviations = [ 'foo', 'bar' ] } + assert_equal([ 'foo', 'bar' ], @format_o.abbreviations) + assert_equal(abbr[0], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.extra_space = true } + assert_equal(abbr[1], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.abbreviations = [ "Pres" ] } + assert_equal([ "Pres" ], @format_o.abbreviations) + assert_equal(abbr[0], @format_o.format(abbr[0])) + assert_nothing_raised { @format_o.extra_space = false } + assert_equal(abbr[0], @format_o.format(abbr[0])) + end + + # Tests both body_indent and body_indent= + def test_body_indent + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = 7 } + assert_equal(7, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = -3 } + assert_equal(3, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = "9" } + assert_equal(9, @format_o.body_indent) + assert_nothing_raised { @format_o.body_indent = "-2" } + assert_equal(2, @format_o.body_indent) + assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[1]) + end + + # Tests both columns and columns= + def test_columns + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(72, @format_o.columns) + assert_nothing_raised { @format_o.columns = 7 } + assert_equal(7, @format_o.columns) + assert_nothing_raised { @format_o.columns = -3 } + assert_equal(3, @format_o.columns) + assert_nothing_raised { @format_o.columns = "9" } + assert_equal(9, @format_o.columns) + assert_nothing_raised { @format_o.columns = "-2" } + assert_equal(2, @format_o.columns) + assert_nothing_raised { @format_o.columns = 40 } + assert_equal(40, @format_o.columns) + assert_match(/this continent$/, + @format_o.format(GETTYSBURG).split("\n")[1]) + end + + # Tests both extra_space and extra_space= + def test_extra_space + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.extra_space) + assert_nothing_raised { @format_o.extra_space = true } + assert(@format_o.extra_space) + # The behaviour of extra_space is tested in test_abbreviations. There + # is no need to reproduce it here. + end + + # Tests both first_indent and first_indent= + def test_first_indent + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(4, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = 7 } + assert_equal(7, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = -3 } + assert_equal(3, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = "9" } + assert_equal(9, @format_o.first_indent) + assert_nothing_raised { @format_o.first_indent = "-2" } + assert_equal(2, @format_o.first_indent) + assert_match(/^ [^ ]/, @format_o.format(GETTYSBURG).split("\n")[0]) + end + + def test_format_style + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(Text::Format::LEFT_ALIGN, @format_o.format_style) + assert_match(/^November 1863$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert_equal(Text::Format::RIGHT_ALIGN, @format_o.format_style) + assert_match(/^ +November 1863$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert_equal(Text::Format::RIGHT_FILL, @format_o.format_style) + assert_match(/^November 1863 +$/, + @format_o.format(GETTYSBURG).split("\n")[-1]) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert_equal(Text::Format::JUSTIFY, @format_o.format_style) + assert_match(/^of freedom, and that government of the people, by the people, for the$/, + @format_o.format(GETTYSBURG).split("\n")[-3]) + assert_raise(ArgumentError) { @format_o.format_style = 33 } + end + + def test_tag_paragraph + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.tag_paragraph) + assert_nothing_raised { @format_o.tag_paragraph = true } + assert(@format_o.tag_paragraph) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) + end + + def test_tag_text + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.tag_text) + assert_equal(@format_o.format(GETTYSBURG), + Text::Format.new.format(GETTYSBURG)) + assert_nothing_raised { + @format_o.tag_paragraph = true + @format_o.tag_text = ["Gettysburg Address", "---"] + } + assert_not_equal(@format_o.format(GETTYSBURG), + Text::Format.new.format(GETTYSBURG)) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG])) + assert_not_equal(@format_o.paragraphs([GETTYSBURG, GETTYSBURG, + GETTYSBURG]), + Text::Format.new.paragraphs([GETTYSBURG, GETTYSBURG, + GETTYSBURG])) + end + + def test_justify? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.justify?) + assert_nothing_raised { + @format_o.format_style = Text::Format::JUSTIFY + } + assert(@format_o.justify?) + # The format testing is done in test_format_style + end + + def test_left_align? + assert_nothing_raised { @format_o = Text::Format.new } + assert(@format_o.left_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.left_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.left_align?) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert(!@format_o.left_align?) + # The format testing is done in test_format_style + end + + def test_left_margin + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = -3 } + assert_equal(3, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = "9" } + assert_equal(9, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = "-2" } + assert_equal(2, @format_o.left_margin) + assert_nothing_raised { @format_o.left_margin = 7 } + assert_equal(7, @format_o.left_margin) + assert_nothing_raised { + ft = @format_o.format(GETTYSBURG).split("\n") + assert_match(/^ {11}Four score/, ft[0]) + assert_match(/^ {7}November/, ft[-1]) + } + end + + def test_hard_margins + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.hard_margins) + assert_nothing_raised { + @format_o.hard_margins = true + @format_o.columns = 5 + @format_o.first_indent = 0 + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(@format_o.hard_margins) + assert_equal(FIVE_COL, @format_o.format(GETTYSBURG)) + assert_nothing_raised { + @format_o.split_rules |= Text::Format::SPLIT_CONTINUATION + assert_equal(Text::Format::SPLIT_CONTINUATION_FIXED, + @format_o.split_rules) + } + assert_equal(FIVE_CNT, @format_o.format(GETTYSBURG)) + end + + # Tests both nobreak and nobreak_regex, since one is only useful + # with the other. + def test_nobreak + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.nobreak) + assert(@format_o.nobreak_regex.empty?) + assert_nothing_raised { + @format_o.nobreak = true + @format_o.nobreak_regex = { '^this$' => '^continent$' } + @format_o.columns = 77 + } + assert(@format_o.nobreak) + assert_equal({ '^this$' => '^continent$' }, @format_o.nobreak_regex) + assert_match(/^this continent/, + @format_o.format(GETTYSBURG).split("\n")[1]) + end + + def test_right_align? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.right_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(@format_o.right_align?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(!@format_o.right_align?) + assert_nothing_raised { @format_o.format_style = Text::Format::JUSTIFY } + assert(!@format_o.right_align?) + # The format testing is done in test_format_style + end + + def test_right_fill? + assert_nothing_raised { @format_o = Text::Format.new } + assert(!@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_ALIGN + } + assert(!@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::RIGHT_FILL + } + assert(@format_o.right_fill?) + assert_nothing_raised { + @format_o.format_style = Text::Format::JUSTIFY + } + assert(!@format_o.right_fill?) + # The format testing is done in test_format_style + end + + def test_right_margin + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(0, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = -3 } + assert_equal(3, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = "9" } + assert_equal(9, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = "-2" } + assert_equal(2, @format_o.right_margin) + assert_nothing_raised { @format_o.right_margin = 7 } + assert_equal(7, @format_o.right_margin) + assert_nothing_raised { + ft = @format_o.format(GETTYSBURG).split("\n") + assert_match(/^ {4}Four score.*forth on$/, ft[0]) + assert_match(/^November/, ft[-1]) + } + end + + def test_tabstop + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(8, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = 7 } + assert_equal(7, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = -3 } + assert_equal(3, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = "9" } + assert_equal(9, @format_o.tabstop) + assert_nothing_raised { @format_o.tabstop = "-2" } + assert_equal(2, @format_o.tabstop) + end + + def test_text + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal([], @format_o.text) + assert_nothing_raised { @format_o.text = "Test Text" } + assert_equal("Test Text", @format_o.text) + assert_nothing_raised { @format_o.text = ["Line 1", "Line 2"] } + assert_equal(["Line 1", "Line 2"], @format_o.text) + end + + def test_s_new + # new(NilClass) { block } + assert_nothing_raised do + @format_o = Text::Format.new { + self.text = "Test 1, 2, 3" + } + end + assert_equal("Test 1, 2, 3", @format_o.text) + + # new(Hash Symbols) + assert_nothing_raised { @format_o = Text::Format.new(:columns => 72) } + assert_equal(72, @format_o.columns) + + # new(Hash String) + assert_nothing_raised { @format_o = Text::Format.new('columns' => 72) } + assert_equal(72, @format_o.columns) + + # new(Hash) { block } + assert_nothing_raised do + @format_o = Text::Format.new('columns' => 80) { + self.text = "Test 4, 5, 6" + } + end + assert_equal("Test 4, 5, 6", @format_o.text) + assert_equal(80, @format_o.columns) + + # new(Text::Format) + assert_nothing_raised do + fo = Text::Format.new(@format_o) + assert(fo == @format_o) + end + + # new(Text::Format) { block } + assert_nothing_raised do + fo = Text::Format.new(@format_o) { self.columns = 79 } + assert(fo != @format_o) + end + + # new(String) + assert_nothing_raised { @format_o = Text::Format.new("Test A, B, C") } + assert_equal("Test A, B, C", @format_o.text) + + # new(String) { block } + assert_nothing_raised do + @format_o = Text::Format.new("Test X, Y, Z") { self.columns = -5 } + end + assert_equal("Test X, Y, Z", @format_o.text) + assert_equal(5, @format_o.columns) + end + + def test_center + assert_nothing_raised { @format_o = Text::Format.new } + assert_nothing_raised do + ct = @format_o.center(GETTYSBURG.split("\n")).split("\n") + assert_match(/^ Four score and seven years ago our fathers brought forth on this/, ct[0]) + assert_match(/^ not perish from the earth./, ct[-3]) + end + end + + def test_expand + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal(" ", @format_o.expand("\t ")) + assert_nothing_raised { @format_o.tabstop = 4 } + assert_equal(" ", @format_o.expand("\t ")) + end + + def test_unexpand + assert_nothing_raised { @format_o = Text::Format.new } + assert_equal("\t ", @format_o.unexpand(" ")) + assert_nothing_raised { @format_o.tabstop = 4 } + assert_equal("\t ", @format_o.unexpand(" ")) + end + + def test_space_only + assert_equal("", Text::Format.new.format(" ")) + assert_equal("", Text::Format.new.format("\n")) + assert_equal("", Text::Format.new.format(" ")) + assert_equal("", Text::Format.new.format(" \n")) + assert_equal("", Text::Format.new.paragraphs("\n")) + assert_equal("", Text::Format.new.paragraphs(" ")) + assert_equal("", Text::Format.new.paragraphs(" ")) + assert_equal("", Text::Format.new.paragraphs(" \n")) + assert_equal("", Text::Format.new.paragraphs(["\n"])) + assert_equal("", Text::Format.new.paragraphs([" "])) + assert_equal("", Text::Format.new.paragraphs([" "])) + assert_equal("", Text::Format.new.paragraphs([" \n"])) + end + + def test_splendiferous + h = nil + test = "This is a splendiferous test" + assert_nothing_raised { @format_o = Text::Format.new(:columns => 6, :left_margin => 0, :indent => 0, :first_indent => 0) } + assert_match(/^splendiferous$/, @format_o.format(test)) + assert_nothing_raised { @format_o.hard_margins = true } + assert_match(/^lendif$/, @format_o.format(test)) + assert_nothing_raised { h = Object.new } + assert_nothing_raised do + @format_o.split_rules = Text::Format::SPLIT_HYPHENATION + class << h #:nodoc: + def hyphenate_to(word, size) + return ["", word] if size < 2 + [word[0 ... size], word[size .. -1]] + end + end + @format_o.hyphenator = h + end + assert_match(/^iferou$/, @format_o.format(test)) + assert_nothing_raised { h = Object.new } + assert_nothing_raised do + class << h #:nodoc: + def hyphenate_to(word, size, formatter) + return ["", word] if word.size < formatter.columns + [word[0 ... size], word[size .. -1]] + end + end + @format_o.hyphenator = h + end + assert_match(/^ferous$/, @format_o.format(test)) + end + end +end -- cgit v1.2.3 From 5867f9516dac1d8ea7701eecea5cd8797888edde Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Fri, 1 Jan 2010 20:45:28 +1100 Subject: Silence warning of missing init on @config --- actionpack/lib/action_view/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index d69e5109fa..4970c768e8 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -274,6 +274,7 @@ module ActionView #:nodoc: end def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc: + @config = nil @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @controller = controller -- cgit v1.2.3 From ffcd356771a4c7dfb7cde66117131852f486e1c7 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Sun, 3 Jan 2010 11:15:50 +1100 Subject: Updating to Mail 1.5.0, including default values for all Message#field_name methods, can access field objects by calling Message#[:field_name] --- actionmailer/CHANGELOG | 9 ++-- actionmailer/actionmailer.gemspec | 2 +- actionmailer/test/mail_layout_test.rb | 18 +++---- actionmailer/test/mail_service_test.rb | 88 +++++++++++++++++----------------- actionmailer/test/quoting_test.rb | 2 +- actionmailer/test/test_helper_test.rb | 4 +- actionmailer/test/tmail_compat_test.rb | 4 +- 7 files changed, 64 insertions(+), 63 deletions(-) diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index 6f4ba96844..785bf98c55 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,13 +1,14 @@ *Rails 3.0 (pending)* -* ActionMailer::Base :default_implicit_parts_order now is in the sequence of the order you want, no reversing of ordering takes place. The default order now is text/plain, then text/enriched, then text/html and then any other part that is not one of these three. +* The Mail::Message class has helped methods for all the field types that return 'common' defaults for the common use case, so to get the subject, mail.subject will give you a string, mail.date will give you a DateTime object, mail.from will give you an array of address specs (mikel@test.lindsaar.net) etc. If you want to access the field object itself, call mail[:field_name] which will return the field object you want, which you can then chain, like mail[:from].formatted -* Mail does not have "quoted_body", "quoted_subject" etc. All of these are accessed via body.encoded, subject.encoded etc +* Mail#content_type now returns the content_type field as a string. If you want the mime type of a mail, then you call Mail#mime_type (eg, text/plain), if you want the parameters of the content type field, you call Mail#content_type_parameters which gives you a hash, eg {'format' => 'flowed', 'charset' => 'utf-8'} -* Every part of a Mail object returns an object, never a string. So Mail.body returns a Mail::Body class object, need to call #encoded or #decoded to get the string you want. +* ActionMailer::Base :default_implicit_parts_order now is in the sequence of the order you want, no reversing of ordering takes place. The default order now is text/plain, then text/enriched, then text/html and then any other part that is not one of these three. -* By default, a field will return the #decoded value when you send it :to_s and any object that is a container (like header, body etc) will return #encoded value when you send it :to_s +* Mail does not have "quoted_body", "quoted_subject" etc. All of these are accessed via body.encoded, subject.encoded etc +* Every object in a Mail object returns an object, never a string. So Mail.body returns a Mail::Body class object, need to call #encoded or #decoded to get the string you want. * Mail::Message#set_content_type does not exist, it is simply Mail::Message#content_type * Every mail message gets a unique message_id unless you specify one, had to change all the tests that check for equality with expected.encoded == actual.encoded to first replace their message_ids with control values diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 201b56a739..8adea46d35 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| s.homepage = "http://www.rubyonrails.org" s.add_dependency('actionpack', '= 3.0.pre') - s.add_dependency('mail', '~> 1.4.3') + s.add_dependency('mail', '~> 1.5.0') s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*'] s.has_rdoc = true diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb index 84f13a6d3c..0877e7b2cb 100644 --- a/actionmailer/test/mail_layout_test.rb +++ b/actionmailer/test/mail_layout_test.rb @@ -72,12 +72,12 @@ class LayoutMailerTest < Test::Unit::TestCase mail = AutoLayoutMailer.create_multipart(@recipient) # CHANGED: content_type returns an object # assert_equal "multipart/alternative", mail.content_type - assert_equal "multipart/alternative", mail.content_type.string + assert_equal "multipart/alternative", mail.mime_type assert_equal 2, mail.parts.size # CHANGED: content_type returns an object # assert_equal 'text/plain', mail.parts.first.content_type - assert_equal 'text/plain', mail.parts.first.content_type.string + assert_equal 'text/plain', mail.parts.first.mime_type # CHANGED: body returns an object # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body @@ -85,7 +85,7 @@ class LayoutMailerTest < Test::Unit::TestCase # CHANGED: content_type returns an object # assert_equal 'text/html', mail.parts.last.content_type - assert_equal 'text/html', mail.parts.last.content_type.string + assert_equal 'text/html', mail.parts.last.mime_type # CHANGED: body returns an object # assert_equal "Hello from layout text/html multipart", mail.parts.last.body @@ -96,19 +96,19 @@ class LayoutMailerTest < Test::Unit::TestCase mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed") # CHANGED: content_type returns an object # assert_equal "multipart/mixed", mail.content_type - assert_equal "multipart/mixed", mail.content_type.string + assert_equal "multipart/mixed", mail.mime_type assert_equal 2, mail.parts.size # CHANGED: content_type returns an object # assert_equal 'text/plain', mail.parts.first.content_type - assert_equal 'text/plain', mail.parts.first.content_type.string + assert_equal 'text/plain', mail.parts.first.mime_type # CHANGED: body returns an object # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s # CHANGED: content_type returns an object # assert_equal 'text/html', mail.parts.last.content_type - assert_equal 'text/html', mail.parts.last.content_type.string + assert_equal 'text/html', mail.parts.last.mime_type # CHANGED: body returns an object # assert_equal "Hello from layout text/html multipart", mail.parts.last.body assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s @@ -116,13 +116,13 @@ class LayoutMailerTest < Test::Unit::TestCase def test_should_fix_multipart_layout mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain") - assert_equal "multipart/alternative", mail.content_type.string + assert_equal "multipart/alternative", mail.mime_type assert_equal 2, mail.parts.size - assert_equal 'text/plain', mail.parts.first.content_type.string + assert_equal 'text/plain', mail.parts.first.mime_type assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s - assert_equal 'text/html', mail.parts.last.content_type.string + assert_equal 'text/html', mail.parts.last.mime_type assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s end diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb index 152900259d..f66b4a174b 100644 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/mail_service_test.rb @@ -362,13 +362,13 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal 2, created.parts.size assert_equal 2, created.parts.first.parts.size - assert_equal "multipart/mixed", created.content_type.string - assert_equal "multipart/alternative", created.parts[0].content_type.string + assert_equal "multipart/mixed", created.mime_type + assert_equal "multipart/alternative", created.parts[0].mime_type assert_equal "bar", created.parts[0].header['foo'].to_s assert_nil created.parts[0].charset - assert_equal "text/plain", created.parts[0].parts[0].content_type.string - assert_equal "text/html", created.parts[0].parts[1].content_type.string - assert_equal "application/octet-stream", created.parts[1].content_type.string + assert_equal "text/plain", created.parts[0].parts[0].mime_type + assert_equal "text/html", created.parts[0].parts[1].mime_type + assert_equal "application/octet-stream", created.parts[1].mime_type end @@ -380,11 +380,11 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal 1,created.parts.size assert_equal 2,created.parts.first.parts.size - assert_equal "multipart/mixed", created.content_type.string - assert_equal "multipart/alternative", created.parts.first.content_type.string - assert_equal "text/plain", created.parts.first.parts.first.content_type.string + assert_equal "multipart/mixed", created.mime_type + assert_equal "multipart/alternative", created.parts.first.mime_type + assert_equal "text/plain", created.parts.first.parts.first.mime_type assert_equal "Nothing to see here.", created.parts.first.parts.first.body.to_s - assert_equal "text/html", created.parts.first.parts.second.content_type.string + assert_equal "text/html", created.parts.first.parts.second.mime_type assert_equal "test HTML
", created.parts.first.parts.second.body.to_s end @@ -468,8 +468,8 @@ class ActionMailerTest < Test::Unit::TestCase assert_nothing_raised { created = TestMailer.create_custom_templating_extension(@recipient) } assert_not_nil created assert_equal 2, created.parts.length - assert_equal 'text/plain', created.parts[0].content_type.string - assert_equal 'text/html', created.parts[1].content_type.string + assert_equal 'text/plain', created.parts[0].mime_type + assert_equal 'text/html', created.parts[1].mime_type end def test_cancelled_account @@ -731,8 +731,8 @@ Content-Type: text/plain; charset=iso-8859-1 The body EOF mail = Mail.new(msg) - assert_equal "testing testing \326\244", mail.subject.to_s - assert_equal "Subject: =?utf-8?Q?testing_testing_=D6=A4?=\r\n", mail.subject.encoded + assert_equal "testing testing \326\244", mail.subject + assert_equal "Subject: =?utf-8?Q?testing_testing_=D6=A4?=\r\n", mail[:subject].encoded end def test_unquote_7bit_subject @@ -744,8 +744,8 @@ Content-Type: text/plain; charset=iso-8859-1 The body EOF mail = Mail.new(msg) - assert_equal "this == working?", mail.subject.to_s - assert_equal "Subject: this == working?\r\n", mail.subject.encoded + assert_equal "this == working?", mail.subject + assert_equal "Subject: this == working?\r\n", mail[:subject].encoded end def test_unquote_7bit_body @@ -868,7 +868,7 @@ EOF mail = Mail.new(fixture) attachment = mail.attachments.last assert_equal "smime.p7s", attachment.original_filename - assert_equal "application/pkcs7-signature", mail.parts.last.content_type.string + assert_equal "application/pkcs7-signature", mail.parts.last.mime_type end def test_decode_attachment_without_charset @@ -913,7 +913,7 @@ EOF def test_multipart_with_mime_version mail = TestMailer.create_multipart_with_mime_version(@recipient) - assert_equal "1.1", mail.mime_version.version + assert_equal "1.1", mail.mime_version end def test_multipart_with_utf8_subject @@ -929,29 +929,29 @@ EOF def test_explicitly_multipart_messages mail = TestMailer.create_explicitly_multipart_example(@recipient) assert_equal 3, mail.parts.length - assert_equal 'multipart/mixed', mail.content_type.string - assert_equal "text/plain", mail.parts[0].content_type.string + assert_equal 'multipart/mixed', mail.mime_type + assert_equal "text/plain", mail.parts[0].mime_type - assert_equal "text/html", mail.parts[1].content_type.string + assert_equal "text/html", mail.parts[1].mime_type assert_equal "iso-8859-1", mail.parts[1].charset - assert_equal "image/jpeg", mail.parts[2].content_type.string - assert_equal "attachment", mail.parts[2].content_disposition.disposition_type - assert_equal "foo.jpg", mail.parts[2].content_disposition.filename - assert_equal "foo.jpg", mail.parts[2].content_type.filename + assert_equal "image/jpeg", mail.parts[2].mime_type + assert_equal "attachment", mail.parts[2][:content_disposition].disposition_type + assert_equal "foo.jpg", mail.parts[2][:content_disposition].filename + assert_equal "foo.jpg", mail.parts[2][:content_type].filename assert_nil mail.parts[2].charset end def test_explicitly_multipart_with_content_type mail = TestMailer.create_explicitly_multipart_example(@recipient, "multipart/alternative") assert_equal 3, mail.parts.length - assert_equal "multipart/alternative", mail.content_type.string + assert_equal "multipart/alternative", mail.mime_type end def test_explicitly_multipart_with_invalid_content_type mail = TestMailer.create_explicitly_multipart_example(@recipient, "text/xml") assert_equal 3, mail.parts.length - assert_equal 'multipart/mixed', mail.content_type.string + assert_equal 'multipart/mixed', mail.mime_type end def test_implicitly_multipart_messages @@ -960,12 +960,12 @@ EOF mail = TestMailer.create_implicitly_multipart_example(@recipient) assert_equal 3, mail.parts.length assert_equal "1.0", mail.mime_version.to_s - assert_equal "multipart/alternative", mail.content_type.string - assert_equal "text/plain", mail.parts[0].content_type.string + assert_equal "multipart/alternative", mail.mime_type + assert_equal "text/plain", mail.parts[0].mime_type assert_equal "utf-8", mail.parts[0].charset - assert_equal "text/html", mail.parts[1].content_type.string + assert_equal "text/html", mail.parts[1].mime_type assert_equal "utf-8", mail.parts[1].charset - assert_equal "application/x-yaml", mail.parts[2].content_type.string + assert_equal "application/x-yaml", mail.parts[2].mime_type assert_equal "utf-8", mail.parts[2].charset end @@ -974,9 +974,9 @@ EOF mail = TestMailer.create_implicitly_multipart_example(@recipient, nil, ["application/x-yaml", "text/plain"]) assert_equal 3, mail.parts.length - assert_equal "application/x-yaml", mail.parts[0].content_type.string - assert_equal "text/plain", mail.parts[1].content_type.string - assert_equal "text/html", mail.parts[2].content_type.string + assert_equal "application/x-yaml", mail.parts[0].mime_type + assert_equal "text/plain", mail.parts[1].mime_type + assert_equal "text/html", mail.parts[2].mime_type end def test_implicitly_multipart_messages_with_charset @@ -984,14 +984,14 @@ EOF assert_equal "multipart/alternative", mail.header['content-type'].content_type - assert_equal 'iso-8859-1', mail.parts[0].content_type.parameters[:charset] - assert_equal 'iso-8859-1', mail.parts[1].content_type.parameters[:charset] - assert_equal 'iso-8859-1', mail.parts[2].content_type.parameters[:charset] + assert_equal 'iso-8859-1', mail.parts[0].content_type_parameters[:charset] + assert_equal 'iso-8859-1', mail.parts[1].content_type_parameters[:charset] + assert_equal 'iso-8859-1', mail.parts[2].content_type_parameters[:charset] end def test_html_mail mail = TestMailer.create_html_mail(@recipient) - assert_equal "text/html", mail.content_type.string + assert_equal "text/html", mail.mime_type end def test_html_mail_with_underscores @@ -1043,7 +1043,7 @@ EOF assert_equal(4, mail.parts.first.parts.length) assert_equal("This is the first part.", mail.parts.first.parts.first.body.to_s) assert_equal("test.rb", mail.parts.first.parts.second.filename) - assert_equal("flowed", mail.parts.first.parts.fourth.content_type.parameters[:format]) + assert_equal("flowed", mail.parts.first.parts.fourth.content_type_parameters[:format]) assert_equal('smime.p7s', mail.parts.second.filename) end @@ -1081,9 +1081,9 @@ EOF assert !mail.from_addrs.empty? assert !mail.cc_addrs.empty? assert !mail.bcc_addrs.empty? - assert_match(/:/, mail.from_addrs.to_s) - assert_match(/:/, mail.cc_addrs.to_s) - assert_match(/:/, mail.bcc_addrs.to_s) + assert_match(/:/, mail[:from].decoded) + assert_match(/:/, mail[:cc].decoded) + assert_match(/:/, mail[:bcc].decoded) end def test_deliver_with_mail_object @@ -1095,14 +1095,14 @@ EOF def test_multipart_with_template_path_with_dots mail = FunkyPathMailer.create_multipart_with_template_path_with_dots(@recipient) assert_equal 2, mail.parts.length - assert "text/plain", mail.parts[1].content_type.string + assert "text/plain", mail.parts[1].mime_type assert "utf-8", mail.parts[1].charset end def test_custom_content_type_attributes mail = TestMailer.create_custom_content_type_attributes - assert_match %r{format="flowed"}, mail.content_type.encoded - assert_match %r{charset="utf-8"}, mail.content_type.encoded + assert_match %r{format=flowed}, mail.content_type + assert_match %r{charset=utf-8}, mail.content_type end def test_return_path_with_create diff --git a/actionmailer/test/quoting_test.rb b/actionmailer/test/quoting_test.rb index b16d160805..7640f4b086 100644 --- a/actionmailer/test/quoting_test.rb +++ b/actionmailer/test/quoting_test.rb @@ -78,7 +78,7 @@ class QuotingTest < Test::Unit::TestCase mail = Mail.new(IO.read("#{File.dirname(__FILE__)}/fixtures/raw_email_with_partially_quoted_subject")) # CHANGED: subject returns an object now # assert_equal "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail", mail.subject - assert_equal "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail", mail.subject.decoded + assert_equal "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail", mail.subject end private diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 86d22da9bf..1fed26f78f 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -19,8 +19,8 @@ class TestHelperMailerTest < ActionMailer::TestCase def test_setup_creates_the_expected_mailer assert @expected.is_a?(Mail::Message) - assert_equal "1.0", @expected.mime_version.version - assert_equal "text/plain", @expected.content_type.string + assert_equal "1.0", @expected.mime_version + assert_equal "text/plain", @expected.mime_type end def test_mailer_class_is_correctly_inferred diff --git a/actionmailer/test/tmail_compat_test.rb b/actionmailer/test/tmail_compat_test.rb index faa267e3bf..a1ca6a7243 100644 --- a/actionmailer/test/tmail_compat_test.rb +++ b/actionmailer/test/tmail_compat_test.rb @@ -8,7 +8,7 @@ class TmailCompatTest < Test::Unit::TestCase assert_nothing_raised do mail.set_content_type "text/plain" end - assert_equal mail.content_type.string, "text/plain" + assert_equal mail.mime_type, "text/plain" end def test_transfer_encoding_raises_deprecation_warning @@ -17,7 +17,7 @@ class TmailCompatTest < Test::Unit::TestCase assert_nothing_raised do mail.transfer_encoding "base64" end - assert_equal mail.content_transfer_encoding.value, "base64" + assert_equal mail.content_transfer_encoding, "base64" end end -- cgit v1.2.3 From 6fbe9ef2ffb1858027130789246f3ae24a0a182f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 3 Jan 2010 20:39:42 +0100 Subject: Use namespaces in notifications. --- actionmailer/lib/action_mailer/base.rb | 2 +- actionpack/lib/action_controller/caching.rb | 4 ++-- actionpack/lib/action_controller/caching/fragments.rb | 14 ++++++++------ actionpack/lib/action_controller/caching/pages.rb | 8 ++++++-- actionpack/lib/action_controller/metal/logger.rb | 7 ++++--- actionpack/lib/action_view/render/partials.rb | 7 ++++--- actionpack/lib/action_view/render/rendering.rb | 5 +++-- actionpack/test/abstract_unit.rb | 5 ++++- actionpack/test/activerecord/controller_runtime_test.rb | 5 +---- actionpack/test/controller/caching_test.rb | 14 ++++++-------- actionpack/test/controller/logging_test.rb | 2 +- .../active_record/connection_adapters/abstract_adapter.rb | 2 +- activerecord/lib/active_record/railtie.rb | 2 +- activesupport/lib/active_support/cache.rb | 4 ++-- 14 files changed, 44 insertions(+), 37 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 0248e29cb7..fb78a01437 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -500,7 +500,7 @@ module ActionMailer #:nodoc: logger.debug "\n#{mail.encoded}" end - ActiveSupport::Notifications.instrument(:deliver_mail, :mail => mail) do + ActiveSupport::Notifications.instrument("actionmailer.deliver", :mail => mail) do begin self.delivery_method.perform_delivery(mail) if perform_deliveries rescue Exception => e # Net::SMTP errors or sendmail pipe errors diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 69ed84da95..22360735b9 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -62,9 +62,9 @@ module ActionController #:nodoc: end def log_event(name, before, after, instrumenter_id, payload) - if name.to_s =~ /(read|write|cache|expire|exist)_(fragment|page)\??/ + if name.to_s =~ /actioncontroller\.((read|write|expire|exist)_(fragment|page)\??)/ key_or_path = payload[:key] || payload[:path] - human_name = name.to_s.humanize + human_name = $1.humanize duration = (after - before) * 1000 logger.info("#{human_name} #{key_or_path.inspect} (%.1fms)" % duration) else diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index f569d0dd8b..91f781a44d 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -53,7 +53,7 @@ module ActionController #:nodoc: return content unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:write_fragment, :key => key) do + instrument_fragment_cache :write_fragment, key do cache_store.write(key, content, options) end content @@ -64,7 +64,7 @@ module ActionController #:nodoc: return unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:read_fragment, :key => key) do + instrument_fragment_cache :read_fragment, key do cache_store.read(key, options) end end @@ -74,7 +74,7 @@ module ActionController #:nodoc: return unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:exist_fragment?, :key => key) do + instrument_fragment_cache :exist_fragment?, key do cache_store.exist?(key, options) end end @@ -101,16 +101,18 @@ module ActionController #:nodoc: key = fragment_cache_key(key) unless key.is_a?(Regexp) message = nil - ActiveSupport::Notifications.instrument(:expire_fragment, :key => key) do + instrument_fragment_cache :expire_fragment, key do if key.is_a?(Regexp) - message = "Expired fragments matching: #{key.source}" cache_store.delete_matched(key, options) else - message = "Expired fragment: #{key}" cache_store.delete(key, options) end end end + + def instrument_fragment_cache(name, key) + ActiveSupport::Notifications.instrument("actioncontroller.#{name}", :key => key){ yield } + end end end end diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index d46f528c7e..4498abcdbe 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -64,7 +64,7 @@ module ActionController #:nodoc: return unless perform_caching path = page_cache_path(path) - ActiveSupport::Notifications.instrument(:expire_page, :path => path) do + instrument_page_cache :expire_page, path do File.delete(path) if File.exist?(path) end end @@ -75,7 +75,7 @@ module ActionController #:nodoc: return unless perform_caching path = page_cache_path(path) - ActiveSupport::Notifications.instrument(:cache_page, :path => path) do + instrument_page_cache :write_page, path do FileUtils.makedirs(File.dirname(path)) File.open(path, "wb+") { |f| f.write(content) } end @@ -107,6 +107,10 @@ module ActionController #:nodoc: def page_cache_path(path) page_cache_directory + page_cache_file(path) end + + def instrument_page_cache(name, path) + ActiveSupport::Notifications.instrument("actioncontroller.#{name}", :path => path){ yield } + end end # Expires the page that was cached with the +options+ as a key. Example: diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb index 4f4370e5f0..0dcab86f10 100644 --- a/actionpack/lib/action_controller/metal/logger.rb +++ b/actionpack/lib/action_controller/metal/logger.rb @@ -15,7 +15,8 @@ module ActionController attr_internal :view_runtime def process_action(action) - ActiveSupport::Notifications.instrument(:process_action, :controller => self, :action => action) do + ActiveSupport::Notifications.instrument("actioncontroller.process_action", + :controller => self, :action => action) do super end end @@ -50,7 +51,7 @@ module ActionController # This is the hook invoked by ActiveSupport::Notifications.subscribe. # If you need to log any event, overwrite the method and do it here. def log_event(name, before, after, instrumenter_id, payload) #:nodoc: - if name == :process_action + if name == "actioncontroller.process_action" duration = [(after - before) * 1000, 0.01].max controller = payload[:controller] request = controller.request @@ -66,7 +67,7 @@ module ActionController message << " [#{request.request_uri rescue "unknown"}]" logger.info(message) - elsif name == :render_template + elsif name == "actionview.render_template" # TODO Make render_template logging work if you are using just ActionView duration = (after - before) * 1000 message = "Rendered #{payload[:identifier]}" diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 5158415c20..4459ef6124 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -215,12 +215,13 @@ module ActionView options = @options if @collection - ActiveSupport::Notifications.instrument(:render_collection, :path => @path, - :count => @collection.size) do + ActiveSupport::Notifications.instrument("actionview.render_collection", + :path => @path, :count => @collection.size) do render_collection end else - content = ActiveSupport::Notifications.instrument(:render_partial, :path => @path) do + content = ActiveSupport::Notifications.instrument("actionview.render_partial", + :path => @path) do render_partial end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 48316cac53..578cfe1177 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -93,7 +93,7 @@ module ActionView def _render_template(template, layout = nil, options = {}) locals = options[:locals] || {} - content = ActiveSupport::Notifications.instrument(:render_template, + content = ActiveSupport::Notifications.instrument("actionview.render_template", :identifier => template.identifier, :layout => (layout ? layout.identifier : nil)) do template.render(self, locals) end @@ -109,7 +109,8 @@ module ActionView end def _render_layout(layout, locals, &block) - ActiveSupport::Notifications.instrument(:render_layout, :identifier => layout.identifier) do + ActiveSupport::Notifications.instrument("actionview.render_layout", + :identifier => layout.identifier) do layout.render(self, locals){ |*name| _layout_for(*name, &block) } end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 8c65087898..c1aebefc77 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -96,7 +96,6 @@ class ActiveSupport::TestCase end class MockLogger - attr_reader :logged attr_accessor :level def initialize @@ -108,6 +107,10 @@ class MockLogger @logged << args.first @logged << blk.call if block_given? end + + def logged + @logged.compact.map { |l| l.to_s.strip } + end end class ActionController::IntegrationTest < ActiveSupport::TestCase diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb index 0f534da14b..6f30bec8ee 100644 --- a/actionpack/test/activerecord/controller_runtime_test.rb +++ b/actionpack/test/activerecord/controller_runtime_test.rb @@ -25,7 +25,7 @@ class ARLoggingTest < ActionController::TestCase def test_log_with_active_record get :show wait - assert_match /ActiveRecord runtime/, logs[3] + assert_match /ActiveRecord runtime/, @controller.logger.logged[3] end private @@ -33,7 +33,4 @@ class ARLoggingTest < ActionController::TestCase @controller.logger = MockLogger.new end - def logs - @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} - end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 679eaf7b38..54d1a72f1f 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -630,17 +630,15 @@ class FragmentCachingTest < ActionController::TestCase end def test_fragment_for_logging - fragment_computed = false - events = [] - ActiveSupport::Notifications.subscribe { |*args| events << args } + @controller.logger = MockLogger.new - buffer = 'generated till now -> ' - @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } + fragment_computed = false + @controller.fragment_for('buffer', 'expensive') { fragment_computed = true } + ActiveSupport::Notifications.notifier.wait assert fragment_computed - assert_equal 'generated till now -> ', buffer - ActiveSupport::Notifications.notifier.wait - assert_equal [:exist_fragment?, :write_fragment], events.map(&:first) + assert_match /Exist fragment\? "views\/expensive"/, @controller.logger.logged[0] + assert_match /Write fragment "views\/expensive"/, @controller.logger.logged[1] end end diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 4206dffa7e..6b9db88d83 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -75,6 +75,6 @@ class LoggingTest < ActionController::TestCase end def logs - @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} + @logs ||= @controller.logger.logged end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index d09aa3c4d2..ba12dcd9ce 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -201,7 +201,7 @@ module ActiveRecord protected def log(sql, name) result = nil - ActiveSupport::Notifications.instrument(:sql, :sql => sql, :name => name) do + ActiveSupport::Notifications.instrument("activerecord.sql", :sql => sql, :name => name) do @runtime += Benchmark.ms { result = yield } end result diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 657ee738c0..51eb04c9d0 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -62,7 +62,7 @@ module ActiveRecord initializer "active_record.notifications" do require 'active_support/notifications' - ActiveSupport::Notifications.subscribe("sql") do |name, before, after, instrumenter_id, payload| + ActiveSupport::Notifications.subscribe("activerecord.sql") do |name, before, after, instrumenter_id, payload| ActiveRecord::Base.connection.log_info(payload[:sql], payload[:name], (after - before) * 1000) end end diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index ad238c1d96..25314ffd43 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -247,13 +247,13 @@ module ActiveSupport expires_in || 0 end - def instrument(operation, key, options, &block) + def instrument(operation, key, options) log(operation, key, options) if self.class.instrument payload = { :key => key } payload.merge!(options) if options.is_a?(Hash) - ActiveSupport::Notifications.instrument(:"cache_#{operation}", payload, &block) + ActiveSupport::Notifications.instrument("activesupport.cache_#{operation}", payload){ yield } else yield end -- cgit v1.2.3 From a68165833a7ba50a1e3d731afe8934d19e3ced99 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 4 Jan 2010 03:50:16 +0530 Subject: Add Relation#create_with to explictily specify create scope --- activerecord/lib/active_record/relation.rb | 16 +++++++++------- activerecord/lib/active_record/relation/query_methods.rb | 4 ++++ activerecord/lib/active_record/relation/spawn_methods.rb | 10 ++++++++++ activerecord/test/cases/relations_test.rb | 8 ++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 6b9925d4e7..487b54f27d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -6,7 +6,7 @@ module ActiveRecord attr_reader :relation, :klass attr_writer :readonly, :table - attr_accessor :preload_associations, :eager_load_associations, :includes_associations + attr_accessor :preload_associations, :eager_load_associations, :includes_associations, :create_with_attributes def initialize(klass, relation) @klass, @relation = klass, relation @@ -124,7 +124,7 @@ module ActiveRecord end def reset - @first = @last = @create_scope = @to_sql = @order_clause = nil + @first = @last = @to_sql = @order_clause = @scope_for_create = nil @records = [] self end @@ -163,13 +163,15 @@ module ActiveRecord end def with_create_scope - @klass.send(:with_scope, :create => create_scope) { yield } + @klass.send(:with_scope, :create => scope_for_create) { yield } end - def create_scope - @create_scope ||= wheres.inject({}) do |hash, where| - hash[where.operand1.name] = where.operand2.value if where.is_a?(Arel::Predicates::Equality) - hash + def scope_for_create + @scope_for_create ||= begin + @create_with_attributes || wheres.inject({}) do |hash, where| + hash[where.operand1.name] = where.operand2.value if where.is_a?(Arel::Predicates::Equality) + hash + end end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 525a9cb365..5d7bf0b7bc 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -17,6 +17,10 @@ module ActiveRecord spawn.tap {|r| r.readonly = status } end + def create_with(attributes = {}) + spawn.tap {|r| r.create_with_attributes = attributes } + end + def select(selects) if selects.present? relation = spawn(@relation.project(selects)) diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index a637e97155..4ecee8c634 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -6,6 +6,7 @@ module ActiveRecord relation.preload_associations = @preload_associations relation.eager_load_associations = @eager_load_associations relation.includes_associations = @includes_associations + relation.create_with_attributes = @create_with_attributes relation.table = table relation end @@ -32,6 +33,14 @@ module ActiveRecord merged_order = relation_order.present? ? relation_order : order_clause merged_relation = merged_relation.order(merged_order) + merged_relation.create_with_attributes = @create_with_attributes + + if @create_with_attributes && r.create_with_attributes + merged_relation.create_with_attributes = @create_with_attributes.merge(r.create_with_attributes) + else + merged_relation.create_with_attributes = r.create_with_attributes || @create_with_attributes + end + merged_wheres = @relation.wheres r.wheres.each do |w| @@ -56,6 +65,7 @@ module ActiveRecord end result.readonly = self.readonly unless skips.include?(:readonly) + result.create_with_attributes = @create_with_attributes unless skips.include?(:create_with) result = result.joins(@relation.joins(@relation)) unless skips.include?(:joins) result = result.group(@relation.groupings) unless skips.include?(:group) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index f895f8b8d2..195889f1df 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -545,6 +545,14 @@ class RelationTest < ActiveRecord::TestCase assert_equal 'hen', hen.name end + def test_explicit_create_scope + hens = Bird.where(:name => 'hen') + assert_equal 'hen', hens.new.name + + hens = hens.create_with(:name => 'cock') + assert_equal 'cock', hens.new.name + end + def test_except relation = Post.where(:author_id => 1).order('id ASC').limit(1) assert_equal [posts(:welcome)], relation.all -- cgit v1.2.3 From 53c6984944b03b5de036167a418593dfcd12e886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 3 Jan 2010 23:33:34 +0100 Subject: Add notifications to ActionDispatch::ShowExceptions, this can be used as hooks for plugins like ExceptionNotifier. --- .../action_dispatch/middleware/show_exceptions.rb | 24 ++++++++++++++++++++-- actionpack/test/dispatch/show_exceptions_test.rb | 20 ++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 4ebc8a2ab9..af356707c6 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -1,7 +1,24 @@ require 'active_support/core_ext/exception' +require 'active_support/notifications' require 'action_dispatch/http/request' module ActionDispatch + # This middleware rescues any exception returned by the application and renders + # nice exception pages if it's being rescued locally. + # + # Every time an exception is caught, a notification is published, becoming a good API + # to deal with exceptions. So, if you want send an e-mail through ActionMailer + # everytime this notification is published, you just need to do the following: + # + # ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload| + # ExceptionNotifier.deliver_exception(start, payload) + # end + # + # The payload is a hash which has to pairs: + # + # * :env - Contains the rack env for the given request; + # * :exception - The exception raised; + # class ShowExceptions LOCALHOST = '127.0.0.1'.freeze @@ -44,8 +61,11 @@ module ActionDispatch def call(env) @app.call(env) rescue Exception => exception - raise exception if env['action_dispatch.show_exceptions'] == false - render_exception(env, exception) + ActiveSupport::Notifications.instrument 'action_dispatch.show_exception', + :env => env, :exception => exception do + raise exception if env['action_dispatch.show_exceptions'] == false + render_exception(env, exception) + end end private diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 9f6a93756c..170b157d17 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -104,4 +104,24 @@ class ShowExceptionsTest < ActionController::IntegrationTest assert_response 405 assert_match /ActionController::MethodNotAllowed/, body end + + test "publishes notifications" do + @app, event = ProductionApp, nil + self.remote_addr = '127.0.0.1' + + ActiveSupport::Notifications.subscribe('action_dispatch.show_exception') do |*args| + event = args + end + + get "/" + assert_response 500 + assert_match /puke/, body + + ActiveSupport::Notifications.notifier.wait + + assert_equal 'action_dispatch.show_exception', event.first + assert_kind_of Hash, event.last[:env] + assert_equal 'GET', event.last[:env]["REQUEST_METHOD"] + assert_kind_of RuntimeError, event.last[:exception] + end end -- cgit v1.2.3 From f2d276fefdd620f18bb9fe3524ae9db6da70621d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 3 Jan 2010 23:39:09 +0100 Subject: Ensure no notification is on the queue before running notifications related tests. --- actionpack/test/activerecord/controller_runtime_test.rb | 2 ++ actionpack/test/controller/caching_test.rb | 2 ++ actionpack/test/controller/logging_test.rb | 1 + actionpack/test/dispatch/show_exceptions_test.rb | 3 +++ 4 files changed, 8 insertions(+) diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb index 6f30bec8ee..9525dd8307 100644 --- a/actionpack/test/activerecord/controller_runtime_test.rb +++ b/actionpack/test/activerecord/controller_runtime_test.rb @@ -23,6 +23,8 @@ class ARLoggingTest < ActionController::TestCase end def test_log_with_active_record + # Wait pending notifications to be published + wait get :show wait assert_match /ActiveRecord runtime/, @controller.logger.logged[3] diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 54d1a72f1f..5a8dc0c358 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -630,6 +630,8 @@ class FragmentCachingTest < ActionController::TestCase end def test_fragment_for_logging + # Wait pending notifications to be published + ActiveSupport::Notifications.notifier.wait @controller.logger = MockLogger.new fragment_computed = false diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 6b9db88d83..594cf17312 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -19,6 +19,7 @@ class LoggingTest < ActionController::TestCase def setup super + wait # Wait pending notifications to be published set_logger end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 170b157d17..951fb4a22e 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -106,6 +106,9 @@ class ShowExceptionsTest < ActionController::IntegrationTest end test "publishes notifications" do + # Wait pending notifications to be published + ActiveSupport::Notifications.notifier.wait + @app, event = ProductionApp, nil self.remote_addr = '127.0.0.1' -- cgit v1.2.3 From 3990310a2bedd0dff5753e3e9b1282e686cff0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 00:03:56 +0100 Subject: Use underscore in notification namespaces. --- actionmailer/lib/action_mailer/base.rb | 2 +- actionpack/lib/action_controller/caching.rb | 2 +- actionpack/lib/action_controller/caching/fragments.rb | 2 +- actionpack/lib/action_controller/caching/pages.rb | 2 +- actionpack/lib/action_controller/metal/logger.rb | 6 +++--- actionpack/lib/action_view/render/partials.rb | 4 ++-- actionpack/lib/action_view/render/rendering.rb | 4 ++-- .../lib/active_record/connection_adapters/abstract_adapter.rb | 2 +- activerecord/lib/active_record/railtie.rb | 2 +- activesupport/lib/active_support/cache.rb | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index fb78a01437..c2ffa5a0e9 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -500,7 +500,7 @@ module ActionMailer #:nodoc: logger.debug "\n#{mail.encoded}" end - ActiveSupport::Notifications.instrument("actionmailer.deliver", :mail => mail) do + ActiveSupport::Notifications.instrument("action_mailer.deliver", :mail => mail) do begin self.delivery_method.perform_delivery(mail) if perform_deliveries rescue Exception => e # Net::SMTP errors or sendmail pipe errors diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 22360735b9..5c0d754ad6 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -62,7 +62,7 @@ module ActionController #:nodoc: end def log_event(name, before, after, instrumenter_id, payload) - if name.to_s =~ /actioncontroller\.((read|write|expire|exist)_(fragment|page)\??)/ + if name.to_s =~ /action_controller\.((read|write|expire|exist)_(fragment|page)\??)/ key_or_path = payload[:key] || payload[:path] human_name = $1.humanize duration = (after - before) * 1000 diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index 91f781a44d..a0c5ed797e 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -111,7 +111,7 @@ module ActionController #:nodoc: end def instrument_fragment_cache(name, key) - ActiveSupport::Notifications.instrument("actioncontroller.#{name}", :key => key){ yield } + ActiveSupport::Notifications.instrument("action_controller.#{name}", :key => key){ yield } end end end diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index 4498abcdbe..5797eeebd6 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -109,7 +109,7 @@ module ActionController #:nodoc: end def instrument_page_cache(name, path) - ActiveSupport::Notifications.instrument("actioncontroller.#{name}", :path => path){ yield } + ActiveSupport::Notifications.instrument("action_controller.#{name}", :path => path){ yield } end end diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb index 0dcab86f10..bf5f3b774f 100644 --- a/actionpack/lib/action_controller/metal/logger.rb +++ b/actionpack/lib/action_controller/metal/logger.rb @@ -15,7 +15,7 @@ module ActionController attr_internal :view_runtime def process_action(action) - ActiveSupport::Notifications.instrument("actioncontroller.process_action", + ActiveSupport::Notifications.instrument("action_controller.process_action", :controller => self, :action => action) do super end @@ -51,7 +51,7 @@ module ActionController # This is the hook invoked by ActiveSupport::Notifications.subscribe. # If you need to log any event, overwrite the method and do it here. def log_event(name, before, after, instrumenter_id, payload) #:nodoc: - if name == "actioncontroller.process_action" + if name == "action_controller.process_action" duration = [(after - before) * 1000, 0.01].max controller = payload[:controller] request = controller.request @@ -67,7 +67,7 @@ module ActionController message << " [#{request.request_uri rescue "unknown"}]" logger.info(message) - elsif name == "actionview.render_template" + elsif name == "action_view.render_template" # TODO Make render_template logging work if you are using just ActionView duration = (after - before) * 1000 message = "Rendered #{payload[:identifier]}" diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 4459ef6124..67a8ee4472 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -215,12 +215,12 @@ module ActionView options = @options if @collection - ActiveSupport::Notifications.instrument("actionview.render_collection", + ActiveSupport::Notifications.instrument("action_view.render_collection", :path => @path, :count => @collection.size) do render_collection end else - content = ActiveSupport::Notifications.instrument("actionview.render_partial", + content = ActiveSupport::Notifications.instrument("action_view.render_partial", :path => @path) do render_partial end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 578cfe1177..2fdfad694d 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -93,7 +93,7 @@ module ActionView def _render_template(template, layout = nil, options = {}) locals = options[:locals] || {} - content = ActiveSupport::Notifications.instrument("actionview.render_template", + content = ActiveSupport::Notifications.instrument("action_view.render_template", :identifier => template.identifier, :layout => (layout ? layout.identifier : nil)) do template.render(self, locals) end @@ -109,7 +109,7 @@ module ActionView end def _render_layout(layout, locals, &block) - ActiveSupport::Notifications.instrument("actionview.render_layout", + ActiveSupport::Notifications.instrument("action_view.render_layout", :identifier => layout.identifier) do layout.render(self, locals){ |*name| _layout_for(*name, &block) } end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index ba12dcd9ce..5eedf448a4 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -201,7 +201,7 @@ module ActiveRecord protected def log(sql, name) result = nil - ActiveSupport::Notifications.instrument("activerecord.sql", :sql => sql, :name => name) do + ActiveSupport::Notifications.instrument("active_record.sql", :sql => sql, :name => name) do @runtime += Benchmark.ms { result = yield } end result diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 51eb04c9d0..a35edace19 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -62,7 +62,7 @@ module ActiveRecord initializer "active_record.notifications" do require 'active_support/notifications' - ActiveSupport::Notifications.subscribe("activerecord.sql") do |name, before, after, instrumenter_id, payload| + ActiveSupport::Notifications.subscribe("active_record.sql") do |name, before, after, instrumenter_id, payload| ActiveRecord::Base.connection.log_info(payload[:sql], payload[:name], (after - before) * 1000) end end diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 25314ffd43..6360a4614e 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -253,7 +253,7 @@ module ActiveSupport if self.class.instrument payload = { :key => key } payload.merge!(options) if options.is_a?(Hash) - ActiveSupport::Notifications.instrument("activesupport.cache_#{operation}", payload){ yield } + ActiveSupport::Notifications.instrument("active_support.cache_#{operation}", payload){ yield } else yield end -- cgit v1.2.3 From b0947bf97c0ac313799f6f1ca739b5666f5fe19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 00:31:53 +0100 Subject: Bring generators tests back to life. --- railties/test/generators/generators_test_helper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index fcd0989fd7..35567f7929 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -25,4 +25,8 @@ class GeneratorsTestCase < Rails::Generators::TestCase rescue # Do nothing. end + + def test_truth + # Don't cry test/unit + end end \ No newline at end of file -- cgit v1.2.3 From 090d12b49b80303ad521ce75b01ea89752417303 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 21:32:02 -0500 Subject: Added that ActionController::Base now does helper :all instead of relying on the default ApplicationController in Rails to do it [DHH] --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_controller/base.rb | 2 ++ .../rails/app/templates/app/controllers/application_controller.rb | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 782b4229fb..7673b9fe56 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Added that ActionController::Base now does helper :all instead of relying on the default ApplicationController in Rails to do it [DHH] + * Added ActionDispatch::Request#authorization to access the http authentication header regardless of its proxy hiding [DHH] * Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples: diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index b23be66910..746ab3e6db 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -6,6 +6,8 @@ module ActionController include AbstractController::Layouts include ActionController::Helpers + helper :all # By default, all helpers should be included + include ActionController::HideActions include ActionController::UrlFor include ActionController::Redirecting diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb index 9889b52893..643a7ca16d 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb @@ -2,7 +2,6 @@ # Likewise, all the methods added will be available for all controllers. class ApplicationController < ActionController::Base - helper :all protect_from_forgery filter_parameter_logging :password end -- cgit v1.2.3 From 950e6bb4912bc87e693eab8731920a122bcff2c2 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 21:32:40 -0500 Subject: Remove self-evident comment about how subclasses work --- .../rails/app/templates/app/controllers/application_controller.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb index 643a7ca16d..2cdf4eae54 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb @@ -1,6 +1,3 @@ -# Filters added to this controller apply to all controllers in the application. -# Likewise, all the methods added will be available for all controllers. - class ApplicationController < ActionController::Base protect_from_forgery filter_parameter_logging :password -- cgit v1.2.3 From 51460b5bf296d7f262f8d865f6f6f1d44513c6d4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 21:34:19 -0500 Subject: This comment has been true of all helpers for a long time --- .../generators/rails/app/templates/app/helpers/application_helper.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb index 22a7940eb2..de6be7945c 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb @@ -1,3 +1,2 @@ -# Methods added to this helper will be available to all templates in the application. module ApplicationHelper end -- cgit v1.2.3 From 0422314b29e6b59362eb1111c983740784428b73 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 21:55:48 -0500 Subject: Time zoning should be turned on by default with UTC --- railties/CHANGELOG | 2 ++ railties/lib/rails/application.rb | 18 ++++++++---------- railties/lib/rails/configuration.rb | 4 ++++ .../rails/app/templates/config/application.rb | 7 +++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 0bc1ea32bc..4e61479fb3 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Set config.time_zone to UTC by default [DHH] + * Added default .gitignore (this is just recognizing Git market share, don't throw a hissy if you use another SCM) [DHH] * Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH]. Examples: diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 457eef648c..5e68c05d7c 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -207,18 +207,16 @@ module Rails # Sets the default value for Time.zone # If assigned value cannot be matched to a TimeZone, an exception will be raised. initializer :initialize_time_zone do - if config.time_zone - require 'active_support/core_ext/time/zones' - zone_default = Time.__send__(:get_zone, config.time_zone) - - unless zone_default - raise \ - 'Value assigned to config.time_zone not recognized.' + - 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.' - end + require 'active_support/core_ext/time/zones' + zone_default = Time.__send__(:get_zone, config.time_zone) - Time.zone_default = zone_default + unless zone_default + raise \ + 'Value assigned to config.time_zone not recognized.' + + 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.' end + + Time.zone_default = zone_default end # Set the i18n configuration from config.i18n but special-case for the load_path which should be diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index f0a0d5e55e..7c1d549c9a 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -230,6 +230,10 @@ module Rails def log_level @log_level ||= RAILS_ENV == 'production' ? :info : :debug end + + def time_zone + @time_zone ||= "UTC" + end def i18n @i18n ||= begin diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index ec0729db04..b6c1cef8cd 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -17,15 +17,14 @@ module <%= app_name.classify %> # config.active_record.observers = :cacher, :garbage_collector, :forum_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. - config.time_zone = 'UTC' + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] # config.i18n.default_locale = :de - # Configure generators values. Many other options are available, be sure to - # check the documentation. + # Configure generators values. Many other options are available, be sure to check the documentation. # config.generators do |g| # g.orm :active_record # g.template_engine :erb -- cgit v1.2.3 From 532b11690fa2c4fd2c127ddc7df246c4469ebbc4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 22:02:10 -0500 Subject: Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH] --- activemodel/CHANGELOG | 2 ++ activemodel/lib/active_model/serializers/json.rb | 8 +++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index 26500568ee..7489c0daa5 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH] + * Add validates_format_of :without => /regexp/ option. #430 [Elliot Winkler, Peer Allan] Example : diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index ee6d48bfc6..794de7dc55 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -10,19 +10,17 @@ module ActiveModel included do extend ActiveModel::Naming - cattr_accessor :include_root_in_json, :instance_writer => false + cattr_accessor :include_root_in_json, :instance_writer => true end # Returns a JSON string representing the model. Some configuration is # available through +options+. # - # The option ActiveRecord::Base.include_root_in_json controls the - # top-level behavior of to_json. In a new Rails application, it is set to - # true in initializers/new_rails_defaults.rb. When it is true, + # The option ActiveModel::Base.include_root_in_json controls the + # top-level behavior of to_json. It is true by default. When it is true, # to_json will emit a single root node named after the object's type. For example: # # konata = User.find(1) - # ActiveRecord::Base.include_root_in_json = true # konata.to_json # # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16, # "created_at": "2006/08/01", "awesome": true} } -- cgit v1.2.3 From 6042067c0b20602e72954450e9e8a19dfa8a9f7d Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 19:20:43 -0800 Subject: Changed the default ActiveSupport.use_standard_json_time_format from false to true and ActiveSupport.escape_html_entities_in_json from true to false to match previously announced Rails 3 defaults [DHH] --- activesupport/CHANGELOG | 3 +++ activesupport/lib/active_support/json/encoding.rb | 3 ++- activesupport/lib/active_support/time_with_zone.rb | 7 +++---- .../app/templates/config/initializers/new_rails_defaults.rb | 12 +----------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 9b0a84678a..87ec6f2a2c 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,8 @@ *Edge* +* Changed the default ActiveSupport.use_standard_json_time_format from false to true and +ActiveSupport.escape_html_entities_in_json from true to false to match previously announced Rails 3 defaults [DHH] + * Added Object#presence that returns the object if it's #present? otherwise returns nil [DHH/Colin Kelley] * Add Enumerable#exclude? to bring parity to Enumerable#include? and avoid if !x.include?/else calls [DHH] diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index c8415d5449..8ba45f7ea2 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -114,7 +114,8 @@ module ActiveSupport end end - self.escape_html_entities_in_json = true + self.use_standard_json_time_format = true + self.escape_html_entities_in_json = false end CircularReferenceError = Deprecation::DeprecatedConstantProxy.new('ActiveSupport::JSON::CircularReferenceError', Encoding::CircularReferenceError) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 6b554e7158..710dce78de 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -32,7 +32,6 @@ module ActiveSupport # t.is_a?(Time) # => true # t.is_a?(ActiveSupport::TimeWithZone) # => true class TimeWithZone - def self.name 'Time' # Report class name as 'Time' to thwart type checking end @@ -114,9 +113,9 @@ module ActiveSupport end alias_method :iso8601, :xmlschema - # Coerces the date to a string for JSON encoding. - # - # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set. + # Coerces the date to a string for JSON encoding. The default format is ISO 8601. You can get + # %Y/%m/%d %H:%M:%S +offset style by setting ActiveSupport::JSON::Encoding.use_standard_json_time_format + # to false. # # ==== Examples # diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb index 8ec3186c84..91a8fdb688 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb @@ -4,16 +4,6 @@ # for Rails 3. You can remove this initializer when Rails 3 is released. if defined?(ActiveRecord) - # Include Active Record class name as root for JSON serialized output. - ActiveRecord::Base.include_root_in_json = true - # Store the full class name (including module namespace) in STI type column. ActiveRecord::Base.store_full_sti_class = true -end - -# Use ISO 8601 format for JSON serialized times and dates. -ActiveSupport.use_standard_json_time_format = true - -# Don't escape HTML entities in JSON, leave that for the #json_escape helper. -# if you're including raw json in an HTML page. -ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file +end \ No newline at end of file -- cgit v1.2.3 From 1459c8cc1d6baca324bf2350d8f89f4faa054f18 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 19:30:28 -0800 Subject: Changed ActiveRecord::Base.store_full_sti_class to be true by default reflecting the previously announced Rails 3 default [DHH] --- activerecord/CHANGELOG | 2 ++ activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/base_test.rb | 3 +++ activerecord/test/cases/inheritance_test.rb | 3 +++ activerecord/test/cases/modules_test.rb | 4 ++++ activerecord/test/cases/reflection_test.rb | 4 ++++ 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 4846774deb..fc6f61f121 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Changed ActiveRecord::Base.store_full_sti_class to be true by default reflecting the previously announced Rails 3 default [DHH] + * Add Relation#delete_all. [Pratik Naik] Item.where(:colour => 'red').delete_all diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 7cefba2b82..78b92be849 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -550,7 +550,7 @@ module ActiveRecord #:nodoc: # Determine whether to store the full constant name including namespace when using STI superclass_delegating_accessor :store_full_sti_class - self.store_full_sti_class = false + self.store_full_sti_class = true # Stores the default scope for the class class_inheritable_accessor :default_scoping, :instance_writer => false diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 730d9d8df7..47e7a4bb79 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -2138,8 +2138,11 @@ class BasicsTest < ActiveRecord::TestCase end def test_type_name_with_module_should_handle_beginning + ActiveRecord::Base.store_full_sti_class = false assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person') assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person') + ensure + ActiveRecord::Base.store_full_sti_class = true end def test_to_param_should_return_string diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 73e51fbd91..0672fb938b 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -241,6 +241,7 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase end def test_instantiation_doesnt_try_to_require_corresponding_file + ActiveRecord::Base.store_full_sti_class = false foo = Firm.find(:first).clone foo.ruby_type = foo.type = 'FirmOnTheFly' foo.save! @@ -259,5 +260,7 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase # And instantiate will find the existing constant rather than trying # to require firm_on_the_fly. assert_nothing_raised { assert_kind_of Firm::FirmOnTheFly, Firm.find(foo.id) } + ensure + ActiveRecord::Base.store_full_sti_class = true end end diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index 4f559bcaa5..d781a229f4 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -12,6 +12,8 @@ class ModulesTest < ActiveRecord::TestCase [:Firm, :Client].each do |const| @undefined_consts.merge! const => Object.send(:remove_const, const) if Object.const_defined?(const) end + + ActiveRecord::Base.store_full_sti_class = false end def teardown @@ -19,6 +21,8 @@ class ModulesTest < ActiveRecord::TestCase @undefined_consts.each do |constant, value| Object.send :const_set, constant, value unless value.nil? end + + ActiveRecord::Base.store_full_sti_class = true end def test_module_spanning_associations diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index acd214eb5a..211cf1d449 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -137,6 +137,8 @@ class ReflectionTest < ActiveRecord::TestCase end def test_association_reflection_in_modules + ActiveRecord::Base.store_full_sti_class = false + assert_reflection MyApplication::Business::Firm, :clients_of_firm, :klass => MyApplication::Business::Client, @@ -172,6 +174,8 @@ class ReflectionTest < ActiveRecord::TestCase :klass => MyApplication::Billing::Nested::Firm, :class_name => 'Nested::Firm', :table_name => 'companies' + ensure + ActiveRecord::Base.store_full_sti_class = true end def test_reflection_of_all_associations -- cgit v1.2.3 From 0ad07d9c26321f426d7d4c234d476e71d1537efb Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 19:32:48 -0800 Subject: Removed config/initializers/new_rails_defaults.rb as all frameworks now follow the settings from it [DHH] --- railties/CHANGELOG | 2 ++ .../app/templates/config/initializers/new_rails_defaults.rb | 9 --------- 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 4e61479fb3..fc9277bd28 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Removed config/initializers/new_rails_defaults.rb as all frameworks now follow the settings from it [DHH] + * Set config.time_zone to UTC by default [DHH] * Added default .gitignore (this is just recognizing Git market share, don't throw a hissy if you use another SCM) [DHH] diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb deleted file mode 100644 index 91a8fdb688..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_rails_defaults.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# These settings change the behavior of Rails 2 apps and will be defaults -# for Rails 3. You can remove this initializer when Rails 3 is released. - -if defined?(ActiveRecord) - # Store the full class name (including module namespace) in STI type column. - ActiveRecord::Base.store_full_sti_class = true -end \ No newline at end of file -- cgit v1.2.3 From 437df4a8d3385bd28812cf6ca5662287d5246517 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 19:46:10 -0800 Subject: Describe intent, not implementation --- railties/lib/rails/generators/rails/app/templates/config.ru | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru index acb8435446..2ab821e38d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config.ru +++ b/railties/lib/rails/generators/rails/app/templates/config.ru @@ -1,5 +1,4 @@ -# Require your environment file to bootstrap Rails -require ::File.expand_path('../config/environment', __FILE__) +# This file is used by Rack-based servers to start the application. -# Dispatch the request +require ::File.expand_path('../config/environment', __FILE__) run <%= app_const %>.instance -- cgit v1.2.3 From d7d917335e242f48fae31bc99e6d4ab381244913 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 3 Jan 2010 19:55:21 -0800 Subject: Stop featuring ActiveSupport::TestCase.use_instantiated_fixtures and ActiveSupport::TestCase.use_transactional_fixtures as likely-to-change settings in test/test_helper.rb -- they are not and their values are already set in test_help.rb [DHH] --- .../rails/app/templates/test/test_helper.rb | 25 ---------------------- 1 file changed, 25 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index a16f587d8b..45b551fc7d 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -3,31 +3,6 @@ require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require 'rails/test_help' class ActiveSupport::TestCase - # Transactional fixtures accelerate your tests by wrapping each test method - # in a transaction that's rolled back on completion. This ensures that the - # test database remains unchanged so your fixtures don't have to be reloaded - # between every test method. Fewer database queries means faster tests. - # - # Read Mike Clark's excellent walkthrough at - # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting - # - # Every Active Record database supports transactions except MyISAM tables - # in MySQL. Turn off transactional fixtures in this case; however, if you - # don't care one way or the other, switching from MyISAM to InnoDB tables - # is recommended. - # - # The only drawback to using transactional fixtures is when you actually - # need to test transactions. Since your test is bracketed by a transaction, - # any transactions started in your code will be automatically rolled back. - self.use_transactional_fixtures = true - - # Instantiated fixtures are slow, but give you @david where otherwise you - # would need people(:david). If you don't want to migrate your existing - # test cases which use the @david style and don't mind the speed hit (each - # instantiated fixtures translates to a database query per test method), - # then set this back to true. - self.use_instantiated_fixtures = false - # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests -- cgit v1.2.3 From ae270f597decb66444d91b27509c7dc1fc24a6b6 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 10:09:10 -0600 Subject: Remove rack submodule, 1.1 has been released as a gem. --- .gitmodules | 3 --- Gemfile | 1 - rack | 1 - 3 files changed, 5 deletions(-) delete mode 160000 rack diff --git a/.gitmodules b/.gitmodules index d0be7ff194..fd4fd34d3e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "arel"] path = arel url = git://github.com/rails/arel.git -[submodule "rack"] - path = rack - url = git://github.com/rails/rack.git diff --git a/Gemfile b/Gemfile index 2aca5065f5..78af1d5020 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,6 @@ only :test do end # AP -gem "rack", "1.1.0", :git => "git://github.com/rack/rack.git" gem "rack-test", "0.5.3" gem "RedCloth", ">= 4.2.2" diff --git a/rack b/rack deleted file mode 160000 index 1ffa95c553..0000000000 --- a/rack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1ffa95c55394c862798727ac8b203ecedda8842a -- cgit v1.2.3 From 79438b46382aa08ea83d740247eb16365e6d2327 Mon Sep 17 00:00:00 2001 From: Zach Brock Date: Tue, 24 Nov 2009 23:51:51 -0800 Subject: adding fix for auto linking to master too Signed-off-by: Michael Koziarski --- actionpack/lib/action_view/helpers/text_helper.rb | 2 +- actionpack/test/template/text_helper_test.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 1d92bcb763..be15e227b9 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -567,7 +567,7 @@ module ActionView end link_text = block_given?? yield(href) : href - href = 'http://' + href unless href.index('http') == 0 + href = 'http://' + href unless href =~ %r{^[a-z]+://}i content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation.reverse.join('') end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 08143ba680..088c07b8bb 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -360,6 +360,20 @@ class TextHelperTest < ActionView::TestCase assert_equal %(

#{link10_result} Link

), auto_link("

#{link10_raw} Link

") end + def test_auto_link_other_protocols + silence_warnings do + begin + old_re_value = ActionView::Helpers::TextHelper::AUTO_LINK_RE + ActionView::Helpers::TextHelper.const_set :AUTO_LINK_RE, %r{(ftp://)[^\s<]+} + link_raw = 'ftp://example.com/file.txt' + link_result = generate_result(link_raw) + assert_equal %(Download #{link_result}), auto_link("Download #{link_raw}") + ensure + ActionView::Helpers::TextHelper.const_set :AUTO_LINK_RE, old_re_value + end + end + end + def test_auto_link_already_linked linked1 = generate_result('Ruby On Rails', 'http://www.rubyonrails.com') linked2 = generate_result('www.rubyonrails.com', 'http://www.rubyonrails.com') -- cgit v1.2.3 From bd729344a7ac747cccaeed983d435fc36c905683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 22:10:13 +0100 Subject: Remove deprecated formatted named routes --- actionpack/lib/action_dispatch/routing/route_set.rb | 8 -------- actionpack/test/controller/url_rewriter_test.rb | 18 ------------------ 2 files changed, 26 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index bd397432ce..792762ebd7 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -189,14 +189,6 @@ module ActionDispatch url_for(#{hash_access_method}(opts)) # url_for(hash_for_users_url(opts)) # end # end - #Add an alias to support the now deprecated formatted_* URL. # #Add an alias to support the now deprecated formatted_* URL. - def formatted_#{selector}(*args) # def formatted_users_url(*args) - ActiveSupport::Deprecation.warn( # ActiveSupport::Deprecation.warn( - "formatted_#{selector}() has been deprecated. " + # "formatted_users_url() has been deprecated. " + - "Please pass format to the standard " + # "Please pass format to the standard " + - "#{selector} method instead.", caller) # "users_url method instead.", caller) - #{selector}(*args) # users_url(*args) - end # end protected :#{selector} # protected :users_url end_eval helpers << selector diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index 428f40b9f8..139d91f8ac 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -347,24 +347,6 @@ class UrlWriterTests < ActionController::TestCase end end - def test_formatted_url_methods_are_deprecated - with_routing do |set| - set.draw do |map| - resources :posts - end - # We need to create a new class in order to install the new named route. - kls = Class.new { include ActionController::UrlWriter } - controller = kls.new - params = {:id => 1, :format => :xml} - assert_deprecated do - assert_equal("/posts/1.xml", controller.send(:formatted_post_path, params)) - end - assert_deprecated do - assert_equal("/posts/1.xml", controller.send(:formatted_post_path, 1, :xml)) - end - end - end - def test_multiple_includes_maintain_distinct_options first_class = Class.new { include ActionController::UrlWriter } second_class = Class.new { include ActionController::UrlWriter } -- cgit v1.2.3 From 562a00ba16746bf36b7d8b327fabae3dabfdb122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 22:11:35 +0100 Subject: @_formats initialization should be AbstractController::Base. --- actionpack/lib/abstract_controller/base.rb | 5 +++++ actionpack/lib/abstract_controller/rendering.rb | 6 ------ actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index a6889d5d01..48725ad82a 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -86,6 +86,11 @@ module AbstractController abstract! + # Initialize controller with nil formats. + def initialize #:nodoc: + @_formats = nil + end + # Calls the action going through the entire action dispatch stack. # # The actual method that is called is determined by calling diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 332d86b089..d57136dbb8 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -17,12 +17,6 @@ module AbstractController self._view_paths ||= ActionView::PathSet.new end - # Initialize controller with nil formats. - def initialize(*) #:nodoc: - @_formats = nil - super - end - # An instance of a view class. The default view class is ActionView::Base # # The view class must have the following methods: diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index af356707c6..10f04dcdf6 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -14,7 +14,7 @@ module ActionDispatch # ExceptionNotifier.deliver_exception(start, payload) # end # - # The payload is a hash which has to pairs: + # The payload is a hash which has two pairs: # # * :env - Contains the rack env for the given request; # * :exception - The exception raised; -- cgit v1.2.3 From 45462c5e41a77e600878f7b8b2e41babeef8fe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 22:22:21 +0100 Subject: Expose Instrumenter id in Notifications. --- activesupport/lib/active_support/notifications/instrumenter.rb | 2 ++ activesupport/test/notifications_test.rb | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 0655dd0cb6..3b0b0d8da2 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -4,6 +4,8 @@ require 'active_support/core_ext/module/delegation' module ActiveSupport module Notifications class Instrumenter + attr_reader :id + def initialize(notifier) @id = unique_id @notifier = notifier diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 3ba77ae135..ef6e6d8d22 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -86,6 +86,10 @@ module Notifications assert_equal 2, @notifier.instrument(:awesome) { 1 + 1 } end + def test_instrumenter_exposes_its_id + assert_equal 20, ActiveSupport::Notifications::Instrumenter.new(@notifier).id.size + end + def test_nested_events_can_be_instrumented @notifier.instrument(:awesome, :payload => "notifications") do @notifier.instrument(:wot, :payload => "child") do -- cgit v1.2.3 From cf83a6f16b730f5536d4e11af894a04b24723212 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 15:59:23 -0600 Subject: Autoload AC and AV test case classes --- actionpack/lib/action_controller.rb | 8 +++++--- actionpack/lib/action_controller/test_case.rb | 1 - actionpack/lib/action_view.rb | 2 ++ actionpack/lib/action_view/test_case.rb | 1 - actionpack/test/abstract_unit.rb | 1 - railties/lib/rails/test_help.rb | 4 ---- railties/test/rails_info_controller_test.rb | 1 - 7 files changed, 7 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index d66fc3fcc9..e6cd055a59 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -27,22 +27,24 @@ module ActionController autoload :MimeResponds autoload :RackDelegation autoload :Redirecting - autoload :Rendering autoload :Renderers + autoload :Rendering autoload :RequestForgeryProtection autoload :Rescue autoload :Responder autoload :SessionManagement autoload :Streaming + autoload :Testing autoload :UrlFor autoload :Verification end autoload :Dispatcher, 'action_controller/dispatch/dispatcher' - autoload :PerformanceTest, 'action_controller/deprecated/performance_test' - autoload :Routing, 'action_controller/deprecated' autoload :Integration, 'action_controller/deprecated/integration_test' autoload :IntegrationTest, 'action_controller/deprecated/integration_test' + autoload :PerformanceTest, 'action_controller/deprecated/performance_test' + autoload :Routing, 'action_controller/deprecated' + autoload :TestCase, 'action_controller/test_case' eager_autoload do autoload :RecordIdentifier diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 398ea52495..155db0af8f 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,6 +1,5 @@ require 'active_support/test_case' require 'rack/session/abstract/id' -require 'action_controller/metal/testing' module ActionController class TestRequest < ActionDispatch::TestRequest #:nodoc: diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 8ce6e82524..93aa69c060 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -52,6 +52,8 @@ module ActionView autoload :TemplateHandler, 'action_view/template' autoload :TemplateHandlers, 'action_view/template' end + + autoload :TestCase, 'action_view/test_case' end require 'action_view/erb/util' diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index be9a2ed50d..1ca427505d 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,5 +1,4 @@ require 'active_support/test_case' -require 'action_controller/test_case' module ActionView class Base diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index c1aebefc77..13e4883762 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -20,7 +20,6 @@ require 'action_view/base' require 'action_dispatch' require 'fixture_template' require 'active_support/test_case' -require 'action_view/test_case' require 'active_support/dependencies' activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__) diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 2601765065..696b65f8bf 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -8,10 +8,6 @@ require 'rack/test' require 'test/unit' require 'active_support/core_ext/kernel/requires' -# AP is always present -require 'action_controller/test_case' -require 'action_view/test_case' - require 'action_mailer/test_case' if defined?(ActionMailer) require 'active_model/test_case' if defined?(ActiveModel) diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index 435bd34925..edab27465e 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' require 'action_controller' -require 'action_controller/test_case' require 'rails/info' require 'rails/info_controller' -- cgit v1.2.3 From ce56c36cd392d6ab0505f0dc4df04c3ad2c074f1 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 16:02:30 -0600 Subject: Autoload AM test case class --- actionmailer/test/abstract_unit.rb | 1 - railties/lib/rails/test_help.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index af6f1bc92e..50b8a53006 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -10,7 +10,6 @@ require 'rubygems' require 'test/unit' require 'action_mailer' -require 'action_mailer/test_case' # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 696b65f8bf..c1e7334ab8 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -8,7 +8,6 @@ require 'rack/test' require 'test/unit' require 'active_support/core_ext/kernel/requires' -require 'action_mailer/test_case' if defined?(ActionMailer) require 'active_model/test_case' if defined?(ActiveModel) if defined?(ActiveRecord) -- cgit v1.2.3 From 2601a16ede92566c651c06942294250ea653bd85 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 16:22:39 -0600 Subject: Autoload AS test case --- actionmailer/lib/action_mailer/test_case.rb | 3 --- actionpack/lib/action_controller/test_case.rb | 1 - actionpack/lib/action_dispatch/testing/integration.rb | 1 - actionpack/lib/action_view/test_case.rb | 2 -- actionpack/test/abstract_unit.rb | 1 - activemodel/lib/active_model/test_case.rb | 2 -- activerecord/lib/active_record/fixtures.rb | 1 - activerecord/lib/active_record/test_case.rb | 2 -- activeresource/test/abstract_unit.rb | 1 - activesupport/lib/active_support.rb | 2 ++ activesupport/test/abstract_unit.rb | 1 - railties/lib/rails/console_app.rb | 1 - railties/lib/rails/generators/test_case.rb | 9 ++++----- .../rails/generators/test_unit/plugin/templates/test_helper.rb | 2 -- railties/test/abstract_unit.rb | 1 - 15 files changed, 6 insertions(+), 24 deletions(-) diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index e8632d4559..318a1e46d1 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -1,6 +1,3 @@ -require 'active_support/test_case' -require 'action_mailer/base' - module ActionMailer class NonInferrableMailerError < ::StandardError def initialize(name) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 155db0af8f..e11e38b20c 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,4 +1,3 @@ -require 'active_support/test_case' require 'rack/session/abstract/id' module ActionController diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 2a5f5dcd5c..4ec47d146c 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,6 +1,5 @@ require 'stringio' require 'uri' -require 'active_support/test_case' require 'active_support/core_ext/object/metaclass' require 'rack/test' diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 1ca427505d..16d66b6eca 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,5 +1,3 @@ -require 'active_support/test_case' - module ActionView class Base alias_method :initialize_without_template_tracking, :initialize diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 13e4883762..27461ce673 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -19,7 +19,6 @@ require 'action_view' require 'action_view/base' require 'action_dispatch' require 'fixture_template' -require 'active_support/test_case' require 'active_support/dependencies' activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__) diff --git a/activemodel/lib/active_model/test_case.rb b/activemodel/lib/active_model/test_case.rb index 4cb5c9cbc0..6328807ad7 100644 --- a/activemodel/lib/active_model/test_case.rb +++ b/activemodel/lib/active_model/test_case.rb @@ -1,5 +1,3 @@ -require "active_support/test_case" - module ActiveModel #:nodoc: class TestCase < ActiveSupport::TestCase #:nodoc: def with_kcode(kcode) diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 99b812b5fc..9da36a87ec 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -3,7 +3,6 @@ require 'yaml' require 'csv' require 'zlib' require 'active_support/dependencies' -require 'active_support/test_case' require 'active_support/core_ext/logger' if RUBY_VERSION < '1.9' diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb index 2dfe2c09ea..0a77ad5fd7 100644 --- a/activerecord/lib/active_record/test_case.rb +++ b/activerecord/lib/active_record/test_case.rb @@ -1,5 +1,3 @@ -require "active_support/test_case" - module ActiveRecord class TestCase < ActiveSupport::TestCase #:nodoc: def assert_date_from_db(expected, actual, message = nil) diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb index 5fa6d3023b..81e582f5c2 100644 --- a/activeresource/test/abstract_unit.rb +++ b/activeresource/test/abstract_unit.rb @@ -10,7 +10,6 @@ require 'rubygems' require 'test/unit' require 'active_resource' require 'active_support' -require 'active_support/test_case' require 'active_model/test_case' $:.unshift "#{File.dirname(__FILE__)}/../test" diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 3463000529..51ec87f329 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -66,6 +66,8 @@ module ActiveSupport autoload :StringInquirer autoload :XmlMini end + + autoload :TestCase end require 'active_support/vendor' diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index dda139372e..d91e0415c4 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -13,7 +13,6 @@ require 'mocha' ENV['NO_RELOAD'] = '1' require 'active_support' -require 'active_support/test_case' # Include shims until we get off 1.8.6 require 'active_support/ruby/shim' diff --git a/railties/lib/rails/console_app.rb b/railties/lib/rails/console_app.rb index 2c4a7a51e8..902a621272 100644 --- a/railties/lib/rails/console_app.rb +++ b/railties/lib/rails/console_app.rb @@ -1,5 +1,4 @@ require 'active_support/all' -require 'active_support/test_case' require 'action_controller' # work around the at_exit hook in test/unit, which kills IRB diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 643d7856c5..38a3cbb035 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -1,4 +1,3 @@ -require 'active_support/test_case' require 'active_support/core_ext/class/inheritable_attributes' require 'active_support/core_ext/hash/reverse_merge' require 'rails/generators' @@ -76,7 +75,7 @@ module Rails eval "$#{stream} = StringIO.new" yield result = eval("$#{stream}").string - ensure + ensure eval("$#{stream} = #{stream.upcase}") end @@ -137,9 +136,9 @@ module Rails # # assert_migration "db/migrate/create_products.rb" # - # This method manipulates the given path and tries to find any migration which + # This method manipulates the given path and tries to find any migration which # matches the migration name. For example, the call above is converted to: - # + # # assert_file "db/migrate/003_create_products.rb" # # Consequently, assert_migration accepts the same arguments has assert_file. @@ -236,4 +235,4 @@ module Rails end end end -end \ No newline at end of file +end diff --git a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb index 348ec33582..2ca36a1e44 100644 --- a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb @@ -1,5 +1,3 @@ require 'rubygems' require 'test/unit' require 'active_support' -require 'active_support/test_case' - diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 2d6983076a..77ef82856a 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -17,7 +17,6 @@ require 'fileutils' require 'active_support' require 'active_support/core_ext/logger' -require 'active_support/test_case' require 'action_controller' require 'rails/all' -- cgit v1.2.3 From 640d9e7e32d9ad67cf81a686aad80266fee7fa61 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 16:29:07 -0600 Subject: Autoload AMo test case --- activemodel/lib/active_model.rb | 7 ++++--- activemodel/test/cases/helper.rb | 1 - activeresource/test/abstract_unit.rb | 1 - railties/lib/rails/test_help.rb | 2 -- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index f14016027c..6eab00c177 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -30,10 +30,12 @@ module ActiveModel extend ActiveSupport::Autoload autoload :AttributeMethods + autoload :BlockValidator, 'active_model/validator' autoload :Callbacks autoload :Conversion autoload :DeprecatedErrorMethods autoload :Dirty + autoload :EachValidator, 'active_model/validator' autoload :Errors autoload :Lint autoload :Name, 'active_model/naming' @@ -42,12 +44,11 @@ module ActiveModel autoload :Observing autoload :Serialization autoload :StateMachine + autoload :TestCase autoload :Translation + autoload :VERSION autoload :Validations autoload :Validator - autoload :EachValidator, 'active_model/validator' - autoload :BlockValidator, 'active_model/validator' - autoload :VERSION module Serializers extend ActiveSupport::Autoload diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index 30193956ea..917bb720d0 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -8,7 +8,6 @@ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) require 'config' require 'active_model' -require 'active_model/test_case' # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb index 81e582f5c2..1e71d5d0dd 100644 --- a/activeresource/test/abstract_unit.rb +++ b/activeresource/test/abstract_unit.rb @@ -10,7 +10,6 @@ require 'rubygems' require 'test/unit' require 'active_resource' require 'active_support' -require 'active_model/test_case' $:.unshift "#{File.dirname(__FILE__)}/../test" require 'setter_trap' diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index c1e7334ab8..e78bbaf825 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -8,8 +8,6 @@ require 'rack/test' require 'test/unit' require 'active_support/core_ext/kernel/requires' -require 'active_model/test_case' if defined?(ActiveModel) - if defined?(ActiveRecord) require 'active_record/test_case' require 'active_record/fixtures' -- cgit v1.2.3 From e5ed62deea3f281f9dafc8e7c9ae4354b5ad6a27 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 16:50:01 -0600 Subject: Autoload AR test case --- actionpack/test/active_record_unit.rb | 1 - activemodel/test/cases/tests_database.rb | 2 -- activerecord/lib/active_record.rb | 3 +++ activerecord/lib/active_record/railties/databases.rake | 5 +---- activerecord/test/cases/helper.rb | 2 -- railties/lib/rails/test_help.rb | 3 --- 6 files changed, 4 insertions(+), 12 deletions(-) diff --git a/actionpack/test/active_record_unit.rb b/actionpack/test/active_record_unit.rb index 9a094cf66b..4f2b052720 100644 --- a/actionpack/test/active_record_unit.rb +++ b/actionpack/test/active_record_unit.rb @@ -17,7 +17,6 @@ unless defined?(ActiveRecord) && defined?(Fixtures) raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) $LOAD_PATH.unshift PATH_TO_AR require 'active_record' - require 'active_record/fixtures' rescue LoadError => e $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}" ActiveRecordTestConnector.able_to_connect = false diff --git a/activemodel/test/cases/tests_database.rb b/activemodel/test/cases/tests_database.rb index 79668dd941..8ca54d2678 100644 --- a/activemodel/test/cases/tests_database.rb +++ b/activemodel/test/cases/tests_database.rb @@ -2,8 +2,6 @@ require 'logger' $:.unshift(File.dirname(__FILE__) + '/../../../activerecord/lib') require 'active_record' -require 'active_record/test_case' -require 'active_record/fixtures' module ActiveModel module TestsDatabase diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 728dec8925..d5b6d40514 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -134,6 +134,9 @@ module ActiveRecord autoload :AbstractAdapter end end + + autoload :TestCase + autoload :TestFixtures, 'active_record/fixtures' end Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index a35a6c156b..492d26c268 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -46,7 +46,7 @@ namespace :db do $stderr.puts "Couldn't create database for #{config.inspect}" end end - return # Skip the else clause of begin/rescue + return # Skip the else clause of begin/rescue else ActiveRecord::Base.establish_connection(config) ActiveRecord::Base.connection @@ -245,7 +245,6 @@ namespace :db do namespace :fixtures do desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures." task :load => :environment do - require 'active_record/fixtures' ActiveRecord::Base.establish_connection(Rails.env) base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures') fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir @@ -257,8 +256,6 @@ namespace :db do desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures." task :identify => :environment do - require "active_record/fixtures" - label, id = ENV["LABEL"], ENV["ID"] raise "LABEL or ID required" if label.blank? && id.blank? diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 479970b2fa..fa76e2d57a 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -13,8 +13,6 @@ require 'test/unit' require 'stringio' require 'active_record' -require 'active_record/test_case' -require 'active_record/fixtures' require 'connection' begin diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index e78bbaf825..feaed50544 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -9,9 +9,6 @@ require 'test/unit' require 'active_support/core_ext/kernel/requires' if defined?(ActiveRecord) - require 'active_record/test_case' - require 'active_record/fixtures' - class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" -- cgit v1.2.3 From 508ffccfe7e67315d82fa2947aa7989e6bfbebc9 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 16:55:27 -0600 Subject: rack and rack-test are pulled in by AD --- railties/lib/rails/test_help.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index feaed50544..4308fc5b82 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -2,9 +2,6 @@ # so fixtures are loaded to the right database silence_warnings { RAILS_ENV = "test" } -require 'rack' -require 'rack/test' - require 'test/unit' require 'active_support/core_ext/kernel/requires' -- cgit v1.2.3 From 947bbc170efc498499911d164eccd05db19a5c63 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 17:13:45 -0600 Subject: Smoke test for test_help --- railties/test/application/test_test.rb | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 railties/test/application/test_test.rb diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb new file mode 100644 index 0000000000..ff6df93ebc --- /dev/null +++ b/railties/test/application/test_test.rb @@ -0,0 +1,38 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class TestTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + end + + test "truth" do + app_file 'test/unit/foo_test.rb', <<-RUBY + require 'test_helper' + + class FooTest < ActiveSupport::TestCase + def test_truth + assert true + end + end + RUBY + + run_test 'unit/foo_test.rb' + end + + private + def run_test(name) + result = ruby '-Itest', "#{app_path}/test/#{name}" + assert_equal 0, $?.to_i, result + end + + def ruby(*args) + Dir.chdir(app_path) do + `RUBYLIB='#{$:.join(':')}' #{Gem.ruby} #{args.join(' ')}` + end + end + end +end -- cgit v1.2.3 From 17f053931ea3bbf583f197d3318eece0b5a771d6 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 17:23:36 -0600 Subject: use_instantiated_fixtures and use_transactional_fixtures defaults are set in active_record/fixtures --- railties/lib/rails/test_help.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 4308fc5b82..e76c476bfb 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -9,8 +9,6 @@ if defined?(ActiveRecord) class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" - self.use_instantiated_fixtures = false - self.use_transactional_fixtures = true end ActionController::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path -- cgit v1.2.3 From 952e449fc0b9adce240df6197a189d179f5e5b7f Mon Sep 17 00:00:00 2001 From: Carlhuda Date: Mon, 4 Jan 2010 16:32:43 -0800 Subject: Fix --dev option --- railties/lib/rails/generators/rails/app/templates/Gemfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 59c6d333e2..7b5c89c3e2 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -5,7 +5,8 @@ gem "rails", "<%= Rails::VERSION::STRING %>" ## Bundle edge rails: <%- if options.dev? -%> -gem "rails", :path => "<%= Rails::Generators::RAILS_DEV_PATH %>" +directory "<%= Rails::Generators::RAILS_DEV_PATH %>", :glob => "{*/,}*.gemspec" +gem "rails", "<%= Rails::VERSION::STRING %>" <%- else -%> <%= "# " unless options.edge? %>gem "rails", :git => "git://github.com/rails/rails.git" <%- end -%> -- cgit v1.2.3 From 6591a10b1f6eccc91bc01ab708050884058e9665 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 4 Jan 2010 17:00:47 -0800 Subject: Reinstate explicit active_support/test_case require since console_app interacts with a non-autoloaded constant --- railties/lib/rails/console_app.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/console_app.rb b/railties/lib/rails/console_app.rb index 902a621272..2c4a7a51e8 100644 --- a/railties/lib/rails/console_app.rb +++ b/railties/lib/rails/console_app.rb @@ -1,4 +1,5 @@ require 'active_support/all' +require 'active_support/test_case' require 'action_controller' # work around the at_exit hook in test/unit, which kills IRB -- cgit v1.2.3 From 56b28ec8d6b226414fb240d4d4f6f1bd25292dc9 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 19:34:42 -0600 Subject: Middleware configuration tests --- railties/test/application/middleware_test.rb | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 railties/test/application/middleware_test.rb diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb new file mode 100644 index 0000000000..1b9c8c30fc --- /dev/null +++ b/railties/test/application/middleware_test.rb @@ -0,0 +1,67 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class MiddlewareTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + test "default middleware stack" do + boot! + + assert_equal [ + "ActionDispatch::Static", + "Rack::Lock", + "Rack::Runtime", + "ActionDispatch::ShowExceptions", + "ActionDispatch::Callbacks", + "ActionDispatch::Session::CookieStore", + "ActionDispatch::ParamsParser", + "Rack::MethodOverride", + "Rack::Head", + "ActionDispatch::StringCoercion", + "ActiveRecord::ConnectionAdapters::ConnectionManagement", + "ActiveRecord::QueryCache" + ], middleware + end + + test "removing activerecord omits its middleware" do + use_frameworks [] + boot! + assert !middleware.include?("ActiveRecord::ConnectionAdapters::ConnectionManagement") + assert !middleware.include?("ActiveRecord::QueryCache") + end + + test "removes lock if allow concurrency is set" do + add_to_config "config.action_controller.allow_concurrency = true" + boot! + assert !middleware.include?("Rack::Lock") + end + + test "removes static asset server if serve_static_assets is disabled" do + add_to_config "config.serve_static_assets = false" + boot! + assert !middleware.include?("ActionDispatch::Static") + end + + test "use middleware" do + use_frameworks [] + add_to_config "config.middleware.use Rack::Config" + boot! + assert_equal "Rack::Config", middleware.last + end + + private + def boot! + require "#{app_path}/config/environment" + end + + def middleware + AppTemplate::Application.instance.middleware.active.map(&:klass).map(&:name) + end + end +end -- cgit v1.2.3 From 76b5f18feba3f1d0507b4c4ec34d11d9bb1c493c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 19:38:56 -0600 Subject: Default middleware stack needs to be available at configuration time --- actionpack/lib/action_controller/railtie.rb | 20 -------------------- railties/lib/rails/configuration.rb | 20 +++++++++++++++++--- railties/test/application/middleware_test.rb | 12 ++++++++++++ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index f861d12905..6b94c32b2a 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -23,26 +23,6 @@ module ActionController app.reload_routes! end - # Include middleware to serve up static assets - initializer "action_controller.initialize_static_server" do |app| - if app.config.serve_static_assets - app.config.middleware.use(ActionDispatch::Static, Rails.public_path) - end - end - - initializer "action_controller.initialize_middleware_stack" do |app| - middleware = app.config.middleware - middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency }) - middleware.use(::Rack::Runtime) - middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local }) - middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request }) - middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) - middleware.use(ActionDispatch::ParamsParser) - middleware.use(::Rack::MethodOverride) - middleware.use(::Rack::Head) - middleware.use(ActionDispatch::StringCoercion) - end - initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 7c1d549c9a..7929cba2fe 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -4,11 +4,25 @@ module Rails # Temporarily separate the plugin configuration class from the main # configuration class while this bit is being cleaned up. class Railtie::Configuration - def self.default @default ||= new end + def self.default_middleware_stack + ActionDispatch::MiddlewareStack.new.tap do |middleware| + middleware.use('ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { Rails.application.config.serve_static_assets }) + middleware.use('::Rack::Lock', :if => lambda { !ActionController::Base.allow_concurrency }) + middleware.use('::Rack::Runtime') + middleware.use('ActionDispatch::ShowExceptions', lambda { ActionController::Base.consider_all_requests_local }) + middleware.use('ActionDispatch::Callbacks', lambda { ActionController::Dispatcher.prepare_each_request }) + middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) + middleware.use('ActionDispatch::ParamsParser') + middleware.use('::Rack::MethodOverride') + middleware.use('::Rack::Head') + middleware.use('ActionDispatch::StringCoercion') + end + end + attr_reader :middleware def initialize(base = nil) @@ -17,7 +31,7 @@ module Rails @middleware = base.middleware.dup else @options = Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new } - @middleware = ActionDispatch::MiddlewareStack.new + @middleware = self.class.default_middleware_stack end end @@ -230,7 +244,7 @@ module Rails def log_level @log_level ||= RAILS_ENV == 'production' ? :info : :debug end - + def time_zone @time_zone ||= "UTC" end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 1b9c8c30fc..df564011d3 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -55,6 +55,18 @@ module ApplicationTests assert_equal "Rack::Config", middleware.last end + test "insert middleware after" do + add_to_config "config.middleware.insert_after ActionDispatch::Static, Rack::Config" + boot! + assert_equal "Rack::Config", middleware.second + end + + test "insert middleware before" do + add_to_config "config.middleware.insert_before ActionDispatch::Static, Rack::Config" + boot! + assert_equal "Rack::Config", middleware.first + end + private def boot! require "#{app_path}/config/environment" -- cgit v1.2.3 From 3f28e0bda6386ed25d07182dd39b84f6a7d330da Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 19:46:21 -0600 Subject: Trash string coercion rack hacks --- actionpack/lib/action_dispatch.rb | 1 - .../action_dispatch/middleware/string_coercion.rb | 29 ---------------- actionpack/test/abstract_unit.rb | 1 - actionpack/test/dispatch/string_coercion_test.rb | 40 ---------------------- railties/lib/rails/configuration.rb | 1 - railties/test/application/middleware_test.rb | 1 - 6 files changed, 73 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/string_coercion.rb delete mode 100644 actionpack/test/dispatch/string_coercion_test.rb diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 1e87a016f9..ad6d54b6a2 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -47,7 +47,6 @@ module ActionDispatch autoload :Rescue autoload :ShowExceptions autoload :Static - autoload :StringCoercion end autoload :MiddlewareStack, 'action_dispatch/middleware/stack' diff --git a/actionpack/lib/action_dispatch/middleware/string_coercion.rb b/actionpack/lib/action_dispatch/middleware/string_coercion.rb deleted file mode 100644 index 232e947835..0000000000 --- a/actionpack/lib/action_dispatch/middleware/string_coercion.rb +++ /dev/null @@ -1,29 +0,0 @@ -module ActionDispatch - class StringCoercion - class UglyBody < ActiveSupport::BasicObject - def initialize(body) - @body = body - end - - def each - @body.each do |part| - yield part.to_s - end - end - - private - def method_missing(*args, &block) - @body.__send__(*args, &block) - end - end - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - [status, headers, UglyBody.new(body)] - end - end -end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 27461ce673..3f7a5c89b9 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -114,7 +114,6 @@ end class ActionController::IntegrationTest < ActiveSupport::TestCase def self.build_app(routes = nil) ActionDispatch::MiddlewareStack.new { |middleware| - middleware.use "ActionDispatch::StringCoercion" middleware.use "ActionDispatch::ShowExceptions" middleware.use "ActionDispatch::Callbacks" middleware.use "ActionDispatch::ParamsParser" diff --git a/actionpack/test/dispatch/string_coercion_test.rb b/actionpack/test/dispatch/string_coercion_test.rb deleted file mode 100644 index d79b17b932..0000000000 --- a/actionpack/test/dispatch/string_coercion_test.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'abstract_unit' - -class StringCoercionTest < ActiveSupport::TestCase - test "body responds to each" do - original_body = [] - body = ActionDispatch::StringCoercion::UglyBody.new(original_body) - - assert original_body.respond_to?(:each) - assert body.respond_to?(:each) - end - - test "body responds to to_path" do - original_body = [] - def original_body.to_path; end - body = ActionDispatch::StringCoercion::UglyBody.new(original_body) - - assert original_body.respond_to?(:to_path) - assert body.respond_to?(:to_path) - end - - test "body does not responds to to_path" do - original_body = [] - body = ActionDispatch::StringCoercion::UglyBody.new(original_body) - - assert !original_body.respond_to?(:to_path) - assert !body.respond_to?(:to_path) - end - - test "calls to_s on body parts" do - app = lambda { |env| - [200, {'Content-Type' => 'html'}, [1, 2, 3]] - } - app = ActionDispatch::StringCoercion.new(app) - parts = [] - status, headers, body = app.call({}) - body.each { |part| parts << part } - - assert_equal %w( 1 2 3 ), parts - end -end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 7929cba2fe..e976c971f0 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -19,7 +19,6 @@ module Rails middleware.use('ActionDispatch::ParamsParser') middleware.use('::Rack::MethodOverride') middleware.use('::Rack::Head') - middleware.use('ActionDispatch::StringCoercion') end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index df564011d3..397968a4e7 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -23,7 +23,6 @@ module ApplicationTests "ActionDispatch::ParamsParser", "Rack::MethodOverride", "Rack::Head", - "ActionDispatch::StringCoercion", "ActiveRecord::ConnectionAdapters::ConnectionManagement", "ActiveRecord::QueryCache" ], middleware -- cgit v1.2.3 From 5c527c2f61d43641f3efa32c960234bc71c6e95e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 4 Jan 2010 19:44:13 -0800 Subject: Controller tests should always require view tests since they add behavior controllers expect --- actionpack/lib/action_controller/test_case.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index e11e38b20c..7e6da0e61d 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,4 +1,5 @@ require 'rack/session/abstract/id' +require 'action_view/test_case' module ActionController class TestRequest < ActionDispatch::TestRequest #:nodoc: -- cgit v1.2.3 From 38f669766cb4d328e121afab020f4a52ca45421f Mon Sep 17 00:00:00 2001 From: Dan Croak Date: Tue, 5 Jan 2010 10:13:29 -0600 Subject: Rails layouts, error pages, and public/index now use HTML5. The specification allows the character encoding meta tag to be removed if character encoding is set at the transport level (Content-Type), which Rails is doing. http://dev.w3.org/html5/html4-differences/#character-encoding Signed-off-by: Joshua Peek --- railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb | 1 - railties/lib/rails/generators/rails/app/templates/public/404.html | 1 - railties/lib/rails/generators/rails/app/templates/public/422.html | 1 - railties/lib/rails/generators/rails/app/templates/public/500.html | 1 - railties/lib/rails/generators/rails/app/templates/public/index.html | 1 - 5 files changed, 5 deletions(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb index 51c4ad0e2e..7aa049fe80 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb @@ -1,7 +1,6 @@ - <%= controller_class_name %>: <%%= controller.action_name %> <%%= stylesheet_link_tag 'scaffold' %> diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index 88ee108e90..9a48320a5f 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -1,7 +1,6 @@ - The page you were looking for doesn't exist (404)