Module: Philiprehberger::WordWrap
- Defined in:
- lib/philiprehberger/word_wrap.rb,
lib/philiprehberger/word_wrap/version.rb
Constant Summary collapse
- ANSI_PATTERN =
/\e\[[0-9;]*m/- VERSION =
'0.4.0'
Class Method Summary collapse
-
.center(text, width: 80) ⇒ String
Center text within a given width.
-
.columns(texts, widths:, separator: ' ') ⇒ String
Format multiple strings into parallel columns.
-
.fit(text, width:, height:, omission: '...') ⇒ String
Wrap text to width, then truncate to at most height lines.
-
.hanging_indent(text, width, indent:) ⇒ String
Wrap text with a hanging indent where the first line is flush left and subsequent lines are indented.
-
.paragraphs(text, width, spacing: 1) ⇒ String
Split on double newlines, wrap each paragraph independently, and rejoin with spacing blank lines.
-
.strip_ansi(text) ⇒ String
Remove ANSI escape codes from text, returning the plain visible string.
- .truncate(text, width: 80, omission: '...') ⇒ Object
-
.unwrap(text) ⇒ String
Remove single newlines within paragraphs (rejoin soft-wrapped text) while preserving paragraph boundaries (double newlines).
- .visible_width(text) ⇒ Object
- .wrap(text, width: 80, indent: nil, first_indent: nil, justify: false) ⇒ Object
Class Method Details
.center(text, width: 80) ⇒ String
Center text within a given width
50 51 52 53 54 55 56 |
# File 'lib/philiprehberger/word_wrap.rb', line 50 def center(text, width: 80) text.split("\n").map do |line| vis_width = visible_width(line.strip) padding = [(width - vis_width) / 2, 0].max "#{' ' * padding}#{line.strip}" end.join("\n") end |
.columns(texts, widths:, separator: ' ') ⇒ String
Format multiple strings into parallel columns
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/philiprehberger/word_wrap.rb', line 64 def columns(texts, widths:, separator: ' ') wrapped = texts.each_with_index.map do |text, i| wrap(text, width: widths[i]).split("\n") end max_lines = wrapped.map(&:length).max || 0 (0...max_lines).map do |line_idx| wrapped.each_with_index.map do |col_lines, col_idx| line = col_lines[line_idx] || '' pad_width = widths[col_idx] vis = visible_width(line) line + (' ' * [(pad_width - vis), 0].max) end.join(separator) end.join("\n") end |
.fit(text, width:, height:, omission: '...') ⇒ String
Wrap text to width, then truncate to at most height lines
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/philiprehberger/word_wrap.rb', line 100 def fit(text, width:, height:, omission: '...') wrapped = wrap(text, width: width) lines = wrapped.split("\n") return wrapped if lines.length <= height truncated_lines = lines[0...height] last_line = truncated_lines.last omission_width = visible_width(omission) available = width - omission_width truncated_lines[-1] = if available <= 0 omission[0...width] elsif visible_width(last_line) > available truncate_at_word_boundary(last_line, available) + omission else "#{last_line}#{omission}" end truncated_lines.join("\n") end |
.hanging_indent(text, width, indent:) ⇒ String
Wrap text with a hanging indent where the first line is flush left and subsequent lines are indented
88 89 90 91 |
# File 'lib/philiprehberger/word_wrap.rb', line 88 def hanging_indent(text, width, indent:) indent_str = ' ' * indent wrap(text, width: width, first_indent: '', indent: indent_str) end |
.paragraphs(text, width, spacing: 1) ⇒ String
Split on double newlines, wrap each paragraph independently, and rejoin with spacing blank lines
129 130 131 132 133 134 |
# File 'lib/philiprehberger/word_wrap.rb', line 129 def paragraphs(text, width, spacing: 1) parts = text.split(/\n{2,}/) wrapped_parts = parts.map { |para| wrap(para.strip, width: width) } separator = "\n#{"\n" * spacing}" wrapped_parts.join(separator) end |
.strip_ansi(text) ⇒ String
Remove ANSI escape codes from text, returning the plain visible string.
41 42 43 |
# File 'lib/philiprehberger/word_wrap.rb', line 41 def strip_ansi(text) text.gsub(ANSI_PATTERN, '') end |
.truncate(text, width: 80, omission: '...') ⇒ Object
23 24 25 26 27 28 29 30 31 |
# File 'lib/philiprehberger/word_wrap.rb', line 23 def truncate(text, width: 80, omission: '...') return text if visible_width(text) <= width omission_width = visible_width(omission) available = width - omission_width return omission if available <= 0 truncate_at_word_boundary(text, available) + omission end |
.unwrap(text) ⇒ String
Remove single newlines within paragraphs (rejoin soft-wrapped text) while preserving paragraph boundaries (double newlines)
141 142 143 144 |
# File 'lib/philiprehberger/word_wrap.rb', line 141 def unwrap(text) paragraphs = text.split(/\n{2,}/) paragraphs.map { |para| para.gsub("\n", ' ').squeeze(' ').strip }.join("\n\n") end |
.visible_width(text) ⇒ Object
33 34 35 |
# File 'lib/philiprehberger/word_wrap.rb', line 33 def visible_width(text) text.gsub(ANSI_PATTERN, '').length end |
.wrap(text, width: 80, indent: nil, first_indent: nil, justify: false) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/philiprehberger/word_wrap.rb', line 10 def wrap(text, width: 80, indent: nil, first_indent: nil, justify: false) indent ||= '' first_indent ||= indent paragraphs = text.split("\n") wrapped_paragraphs = paragraphs.map do |paragraph| wrap_paragraph(paragraph, width: width, indent: indent, first_indent: first_indent) end result = wrapped_paragraphs.join("\n") justify ? justify_text(result, width) : result end |