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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
# File 'lib/textwrap.rb', line 23
def wrap(text, width = 70, options = {})
if width.kind_of?(Hash)
options = width
width = options.fetch(:width, 70)
end
initial_indent = options.fetch(:initial_indent, '')
subsequent_indent = options.fetch(:subsequent_indent, '')
break_long_words = options.fetch(:break_long_words, true)
code = options.fetch(:code, $KCODE)
if (m = /\A[esu]/i.match(code))
code = m[0].downcase
else
code = 'n'
end
if options.fetch(:expand_tabs, true)
text = text.gsub(/\t/, ' ') end
if options.fetch(:replace_whitespace, true)
text = text.gsub(/\t\f/, ' ')
end
if options.has_key?(:consider_linebreak_whitespace)
consider_linebreak_whitespace = options[:consider_linebreak_whitespace]
elsif code == 'n'
consider_linebreak_whitespace = true
else
consider_linebreak_whitespace = false
end
gauge_width = lambda {|str|
w = 0
str.scan(Regexp.new('.', nil, code)) do |c|
w += (c[0] <= 0x7f) ? 1 : 2
end
return w
}
if options.fetch(:break_long_words, true)
break_word = lambda {|src, scnr|
return [src, scnr] if gauge_width.call(src) <= width
w = 0; dest = ''
src.scan(Regexp.new('.', nil, code)) do |c|
w += (c[0] <= 0x7f) ? 1 : 2
break if w > width
dest << c
end
new_scnr = StringScanner.new(src.slice(dest.length..-1) + scnr.rest)
return [dest, new_scnr]
}
else
break_word = lambda {|str, scnr| [str, scnr]}
end
regexps = [/\s+/, /\S+/]
s = StringScanner.new(text.split(/[\r\n]+/).join(consider_linebreak_whitespace ? ' ' : ''))
lines = []
indent = initial_indent
word = s.scan(regexps.reverse!.first) || s.scan(regexps.reverse!.first) || ''
word, s = break_word.call(word, s)
words = [word]
until s.eos?
word = s.scan(regexps.reverse!.first) or next
word, s = break_word.call(word, s)
line = indent + words.join.sub(/\A\s+/, '')
if gauge_width.call(line + word) > width
lines << line.sub(/\s+\Z/, '')
words.clear
indent = subsequent_indent
end
words << word
end
unless words.empty?
lines << indent + words.join.strip
end
return lines
end
|