textwrap for Ruby

textwrapRubyにないので実装してみた。
「すぐ終わるだろ」とか思っていたら、あっという間に深夜…とほほん。
dedentとfix_sentence_endingsは未実装。間違えたトコはない思うけど、正直微妙。
もっと効率のいい書き方があったら、どなたか教えてください、

require 'strscan'

class TextWrapper
  class << self
    def wrap(text, options = {})
      width             = options.fetch(:width, 70)
      initial_indent    = options.fetch(:initial_indent, '')
      subsequent_indent = options.fetch(:subsequent_indent, '')

      if options.fetch(:expand_tabs, true)
        text = text.gsub(/\t/, ' ' * 8)
      end

      if options.fetch(:replace_whitespace, true)
        text = text.gsub(/\s/, ' ')
      end

      if options.fetch(:break_long_words, true)
        rs = [/\s{1,#{width}}/, /\S{1,#{width}}/]
      else
        rs = [/\s+/, /\S+/]
      end

      s = StringScanner.new(text.split($/).join)
      lines = []
      indent = initial_indent
      words = [(s.scan(rs.reverse!.first) or s.scan(rs.reverse!.first) or '')]

      until s.eos?
        word = s.scan(rs.reverse!.first) 
        line = indent + words.join.strip

        if (line + word).length > width
          lines << line
          words.clear
          indent = subsequent_indent
        end

        words << word
      end

      lines << indent + words.join.strip unless words.empty?
    end

    def fill(text, options = {})
      self.wrap(text, options).join("\n")
    end
  end # class method

  attr_accessor :width
  attr_accessor :expand_tabs
  attr_accessor :replace_whitespace
  attr_accessor :initial_indent
  attr_accessor :subsequent_indent
  attr_accessor :break_long_words

  def initialize(options)
    @width              = options.fetch(:width, 70)
    @expand_tabs        = options.fetch(:expand_tabs, true)
    @replace_whitespace = options.fetch(:replace_whitespace, true)
    @initial_indent     = options.fetch(:initial_indent, '')
    @subsequent_indent  = options.fetch(:subsequent_indent, '')
    @break_long_words   = options.fetch(:break_long_words, true)
  end

  def wrap(text, options ={})
    self.class.wrap(text, {
      :width              => @width,
      :expand_tabs        => @expand_tabs,
      :replace_whitespace => @replace_whitespace,
      :initial_indent     => @initial_indent,
      :subsequent_indent  => @subsequent_indent,
      :break_long_words   => @break_long_words
    }.merge(options))
  end

  def fill(text, options = {})
    self.wrap(text, options)
  end
end


irb(main):007:0> puts TextWrapper.fill(< 40)
irb(main):008:1" The wrap() method is just like fill() except that it returns
irb(main):009:1" a list of strings instead of one big string with newlines to separate
irb(main):010:1" the wrapped lines.
irb(main):011:1" EOS
The wrap() method is just like fill()
except that it returns a list of strings
instead of one big string with newlines
to separate the wrapped lines.
=> nil


追記
まじめにキーワード引数もどきを書いてみたいけど、どっかに参考になるコードはないかなぁ…