1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
require 'strscan'

class String
  def interpolation_queue
    @interpolation_queue ||= []
  end
  
  def queue_for_interpolation_at_index(string, index)
    interpolation_queue.push([index, string])
  end
  
  def with_interpolated
    s = self.to_s
    interpolation_queue.length.times do
      index, inter_string = interpolation_queue.shift
      s[index, 0] = inter_string + s[index, 0]
      interpolation_queue.map! do |queue_item|
        settable_index, nothing_important = queue_item
        if settable_index >= index
          [settable_index + inter_string.length, nothing_important]
        else
          queue_item
        end
      end
    end
    s
  end
  
  def scan_for_indices(token)
    ar = []
    indice_fetcher = StringScanner.new(self)
    while indice_fetcher.scan_until(token)
      ar << indice_fetcher.pos - indice_fetcher.matchedsize
    end
    ar
  end
  
  def fatten(length)
    s = self.to_s
    favoured_indices = s.scan_for_indices(/[.?!] +(?!$)/).map { |i| i.succ }
    indices = s.scan_for_indices(/ +(?!$)/)
    0.upto(indices.length-1) do |i|
      if favoured_indices.include?(indices[i])
        indices.concat([indices[i]])
      end
    end
    indices.sort!
    total_length = s.length
    i = 0
    while total_length < length
      s.queue_for_interpolation_at_index(' ', indices[i%indices.length])
      total_length += 1
      i += 1
    end
    s.with_interpolated
  end
  
  def justified(width=nil)
    lines = self.to_a
    unless width
      width = lines.inject(0) { |m, l| [m, l.length].max }
    end
    lines[0..-2].map { |line| line.fatten(width) } << lines.last
  end
end

if __FILE__ == $0
  
  string = <<-EOF.map{|l| l.strip}.join("\n")
  A second issue comes up also, moreover. As Internet
  standards--usually canonicalized in RFCs--have evolved, and
  as Python libraries have become more versatile and robust,
  some newer modules have superceded older ones. In a similar
  way, for example, the [re] module replaced the older [regex]
  module. In the interests of backwards compatibility, Python
  has not dropped any Internet modules from its standard
  distributions. Nonetheless, the [email] module represents
  current "best practice" for most tasks related to email and
  newsgroup message handling. The modules [mimify],
  [mimetools], [MimeWriter], [multifile], and [rfc822] are
  likely to be utilized in existing code, but for new
  applications, it is better to use the capabilities in
  [email] in their stead.
  EOF

  puts string.justified
end