class Text::Format

Introduction

Text::Format provides the ability to nicely format fixed-width text with knowledge of the writeable space (number of columns), margins, and indentation settings.

Copyright

Copyright © 2002 - 2005 by Austin Ziegler

Version

1.0.0

Based On

Perl Text::Format, Copyright © 1998 Gábor Egressy

Licence

Ruby’s, Perl Artistic, or GPL version 2 (or later)

Public Instance Methods

==(o) click to toggle source

Compares the formatting rules, excepting hyphenator, of two Text::Format objects. Generated results (e.g., split_words) are not compared.

# File lib/text/format.rb, line 188
def ==(o)
  (@text                  == o.text)                  and
  (@columns               == o.columns)               and
  (@left_margin           == o.left_margin)           and
  (@right_margin          == o.right_margin)          and
  (@hard_margins          == o.hard_margins)          and
  (@split_rules           == o.split_rules)           and
  (@first_indent          == o.first_indent)          and
  (@body_indent           == o.body_indent)           and
  (@tag_text              == o.tag_text)              and
  (@tabstop               == o.tabstop)               and
  (@format_style          == o.format_style)          and
  (@extra_space           == o.extra_space)           and
  (@tag_paragraph         == o.tag_paragraph)         and
  (@nobreak               == o.nobreak)               and
  (@terminal_punctuation  == o.terminal_punctuation)  and
  (@terminal_quotes       == o.terminal_quotes)       and
  (@abbreviations         == o.abbreviations)         and
  (@nobreak_regex         == o.nobreak_regex)
end
center(to_center = nil) click to toggle source

Centers the text, preserving empty lines and tabs.

# File lib/text/format.rb, line 728
def center(to_center = nil)
  to_center = @text if to_center.nil?
  to_center = [to_center].flatten

  tabs = 0
  width = @columns - @left_margin - @right_margin
  centered = []
  to_center.each do |tc|
    s = tc.strip
    tabs = s.count(TAB)
    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(to_expand = nil) click to toggle source

Replaces all tab characters in the text with tabstop spaces.

# File lib/text/format.rb, line 747
def expand(to_expand = nil)
  to_expand = @text if to_expand.nil?

  tmp = ' ' * @tabstop
  changer = lambda do |text|
    res = text.split(NEWLINE_RE)
    res.collect! { |ln| ln.gsub!(/\t/, tmp) }
    res.join(NEWLINE)
  end

  if to_expand.kind_of?(Array)
    to_expand.collect { |te| changer[te] }
  else
    changer[to_expand]
  end
end
format(text = nil) click to toggle source
format_one_paragraph(text = nil) click to toggle source

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 text is nil, then the value of text will be worked on.

# File lib/text/format.rb, line 550
def format_one_paragraph(text = nil)
  text ||= @text
  text = text[0] if text.kind_of?(Array)

    # Convert the provided paragraph to a list of words.
  words = text.split(SPACES_RE).reverse.reject { |ww| ww.nil? or ww.empty? }

  text = []

    # Find the maximum line width and the initial indent string.
    # TODO 20050114 - allow the left and right margins to be specified as
    # strings. If they are strings, then we need to use the sizes of the
    # strings. Also: allow the indent string to be set manually and
    # indicate whether the indent string will have a following space.
  max_line_width = @columns - @first_indent - @left_margin - @right_margin
  indent_str = ' ' * @first_indent

  first_line = true

  if words.empty?
    line        = []
    line_size   = 0
    extra_space = false
  else
    line        = [ words.pop ]
    line_size   = line[-1].size
    extra_space = __add_extra_space?(line[-1])
  end

  while next_word = words.pop
    next_word.strip! unless next_word.nil?
    new_line_size = (next_word.size + line_size) + 1

    if extra_space
      if (line[-1] !~ __sentence_end_re)
        extra_space = false
      end
    end

      # Increase the width of the new line if there's a sentence
      # terminator and we are applying extra_space.
    new_line_size += 1 if extra_space

      # Will the word fit onto the current line? If so, simply append it
      # to the end of the line.

    if new_line_size <= max_line_width
      if line.empty?
        line << next_word
      else
        if extra_space
          line << "  #{next_word}"
        else
          line << " #{next_word}"
        end
      end
    else
        # Forcibly wrap the line if nonbreaking spaces are turned on and
        # there is a condition where words must be wrapped. If we have
        # returned more than one word, readjust the word list.
      line, next_word = __wrap_line(line, next_word) if @nobreak
      if next_word.kind_of?(Array)
        if next_word.size > 1
          words.push(*(next_word.reverse))
          next_word = words.pop
        else
          next_word = next_word[0]
        end
        next_word.strip! unless next_word.nil?
      end

        # Check to see if the line needs to be hyphenated. If a word has a
        # hyphen in it (e.g., "fixed-width"), then we can ALWAYS wrap at
        # that hyphenation, even if #hard_margins is not turned on. More
        # elaborate forms of hyphenation will only be performed if
        # #hard_margins is turned on. If we have returned more than one
        # word, readjust the word list.
      line, new_line_size, next_word = __hyphenate(line, line_size, next_word, max_line_width)
      if next_word.kind_of?(Array)
        if next_word.size > 1
          words.push(*(next_word.reverse))
          next_word = words.pop
        else
          next_word = next_word[0]
        end
        next_word.strip! unless next_word.nil?
      end

      text << __make_line(line, indent_str, max_line_width, next_word.nil?) unless line.nil?

      if first_line
        first_line = false
        max_line_width = @columns - @body_indent - @left_margin - @right_margin
        indent_str = ' ' * @body_indent
      end

      if next_word.nil?
        line          = []
        new_line_size = 0
      else
        line          = [ next_word ]
        new_line_size = next_word.size
      end
    end

    line_size   = new_line_size
    extra_space = __add_extra_space?(next_word) unless next_word.nil?
  end

  loop do
    break if line.nil? or line.empty?
    line, line_size, ww = __hyphenate(line, line_size, ww, max_line_width)#if @hard_margins
    text << __make_line(line, indent_str, max_line_width, ww.nil?)
    line = ww
    ww = nil
  end

  if (@tag_paragraph and (not text.empty?))
    if @tag_cur.nil? or @tag_cur.empty?
      @tag_cur = @tag_text[0]
    end

    fchar = /(\S)/.match(text[0])[1]
    white = text[0].index(fchar)

    unless @tag_cur.nil?
      if ((white - @left_margin - 1) > @tag_cur.size) then
        white = @tag_cur.size + @left_margin
        text[0].gsub!(/^ {#{white}}/, "#{' ' * @left_margin}#{@tag_cur}")
      else
        text.unshift("#{' ' * @left_margin}#{@tag_cur}\n")
      end
    end
  end

  text.join('')
end
Also aliased as: format
hyphenate_to(word, size) click to toggle source

The formatting object itself can be used as a hyphenator, where the default implementation of hyphenate_to implements the conditions necessary to properly produce SPLIT_CONTINUATION.

# File lib/text/format.rb, line 531
def hyphenate_to(word, size)
  if (size - 2) < 0
    [nil, word]
  else
    [word[0 .. (size - 2)] + "\\", word[(size - 1) .. -1]]
  end
end
justify?() click to toggle source

Indicates that the format style is full justification.

Default

false

Used in

format, paragraphs

# File lib/text/format.rb, line 524
def justify?
  @format_style == JUSTIFY
end
left_align?() click to toggle source

Indicates that the format style is left alignment.

Default

true

Used in

format, paragraphs

# File lib/text/format.rb, line 500
def left_align?
  @format_style == LEFT_ALIGN
end
paragraphs(to_wrap = nil, split_on = /( click to toggle source

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.

If to_wrap responds to split, then it will be split into an array of elements by calling split with the value of split_on. The default value of split_on is $/, or the default record separator, repeated twice (e.g., /nn/).

# File lib/text/format.rb, line 699
def paragraphs(to_wrap = nil, split_on = /(#{$/}){2}/)
  to_wrap = @text if to_wrap.nil?
  if to_wrap.respond_to?(:split)
    to_wrap = to_wrap.split(split_on)
  else
    to_wrap = [to_wrap].flatten
  end

  if ((@first_indent == @body_indent) or @tag_paragraph) then
    p_end = NEWLINE
  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?) and (line.size > 0)
    cnt += 1
  end

  ret[-1].chomp! unless ret.empty?
  ret.join('')
end
right_align?() click to toggle source

Indicates that the format style is right alignment.

Default

false

Used in

format, paragraphs

# File lib/text/format.rb, line 508
def right_align?
  @format_style == RIGHT_ALIGN
end
right_fill?() click to toggle source

Indicates that the format style is right fill.

Default

false

Used in

format, paragraphs

# File lib/text/format.rb, line 516
def right_fill?
  @format_style == RIGHT_FILL
end
split_word_to(word, size) click to toggle source

Splits the provided word so that it is in two parts, word[0 .. (size - 1)] and word[size .. -1].

# File lib/text/format.rb, line 541
def split_word_to(word, size)
  [word[0 .. (size - 1)], word[size .. -1]]
end
unexpand(to_unexpand = nil) click to toggle source

Replaces all occurrences of tabstop consecutive spaces with a tab character.

# File lib/text/format.rb, line 766
def unexpand(to_unexpand = nil)
  to_unexpand = @text if to_unexpand.nil?

  tmp = / {#{@tabstop}}/
  changer = lambda do |text|
    res = text.split(NEWLINE_RE)
    res.collect! { |ln| ln.gsub!(tmp, TAB) }
    res.join(NEWLINE)
  end

  if to_unexpand.kind_of?(Array)
    to_unexpand.collect { |tu| changer[tu] }
  else
    changer[to_unexpand]
  end
end

Public Class Methods

new(options = {}) { |self| ... } click to toggle source

Create a Text::Format object. Accepts an optional hash of construction options (this will be changed to named paramters in Ruby 2.0). After the initial object is constructed (with either the provided or default values), the object will be yielded (as self) to an optional block for further construction and operation.

# File lib/text/format.rb, line 1016
def initialize(options = {}) #:yields self:
  @text                 = options[:text]                  || []
  @columns              = options[:columns]               || 72
  @tabstop              = options[:tabstop]               || 8
  @first_indent         = options[:first_indent]          || 4
  @body_indent          = options[:body_indent]           || 0
  @format_style         = options[:format_style]          || LEFT_ALIGN
  @left_margin          = options[:left_margin]           || 0
  @right_margin         = options[:right_margin]          || 0
  @extra_space          = options[:extra_space]           || false
  @tag_paragraph        = options[:tag_paragraph]         || false
  @tag_text             = options[:tag_text]              || []
  @abbreviations        = options[:abbreviations]         || []
  @terminal_punctuation = options[:terminal_punctuation]  || ""
  @terminal_quotes      = options[:terminal_quotes]       || ""
  @nobreak              = options[:nobreak]               || false
  @nobreak_regex        = options[:nobreak_regex]         || {}
  @hard_margins         = options[:hard_margins]          || false
  @split_rules          = options[:split_rules]           || SPLIT_FIXED
  @hyphenator           = options[:hyphenator]            || self

  @hyphenator_arity     = @hyphenator.method(:hyphenate_to).arity
  @tag_cur              = ""
  @split_words          = []

  yield self if block_given?
end