verse 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +27 -0
- data/lib/verse.rb +2 -0
- data/lib/verse/alignment.rb +11 -5
- data/lib/verse/padding.rb +4 -3
- data/lib/verse/sanitizer.rb +12 -0
- data/lib/verse/truncation.rb +23 -9
- data/lib/verse/version.rb +1 -1
- data/lib/verse/wrapping.rb +71 -14
- data/spec/unit/alignment/align_spec.rb +17 -0
- data/spec/unit/alignment/left_spec.rb +18 -1
- data/spec/unit/alignment/right_spec.rb +18 -1
- data/spec/unit/padding/pad_spec.rb +13 -0
- data/spec/unit/sanitizer/ansi_spec.rb +11 -0
- data/spec/unit/truncation/truncate_spec.rb +2 -2
- data/spec/unit/wrapping/wrap_spec.rb +57 -0
- data/verse.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91a9c0b0722656e5b2b160a14e68f9d228830120
|
4
|
+
data.tar.gz: 9397441752523d44ac885b7e5ad4b0e8faffbead
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa1fb93fb455d0d141616c0a0dd08886486331a92b5b165a3ec1852f228b89e8002fb078d9329b0c9325a758725004ebb14f74c5ba618145de9c29990b2b0519
|
7
|
+
data.tar.gz: bf4deb4d61427c35aab5d4522b31003a49e1b93388e176fd19533dfe3177e618126beee94893de210b14f64b5c51555b707cb7b39b1d17dd168ead985af54c6d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
0.4.0 (Mar 28, 2015)
|
2
|
+
|
3
|
+
* Add Sanitizer#ansi? to check for ANSI codes
|
4
|
+
* Change Alignment to work with ANSI codes
|
5
|
+
* Change Truncation to work with ANSI codes
|
6
|
+
* Change Wrapping to work with ANSI codes
|
7
|
+
* Chnage Padding to work with ANSI codes
|
8
|
+
|
1
9
|
0.3.0 (Feb 28, 2015)
|
2
10
|
|
3
11
|
* Add Sanitizer#replace for substitutiong linebreaks
|
data/README.md
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
* Simple API that can be easily wrapped by other objects
|
20
20
|
* Supports multibyte character encodings such as UTF-8, EUC-JP
|
21
21
|
* Handles languages without whitespaces between words (like Chinese and Japanese)
|
22
|
+
* Supports ANSI escape codes
|
22
23
|
|
23
24
|
## Installation
|
24
25
|
|
@@ -87,6 +88,14 @@ alignment.center(20) # =>
|
|
87
88
|
" 場にも含み "
|
88
89
|
```
|
89
90
|
|
91
|
+
**Verse::Alignment** works with ANSI escape codoes:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
alignment = Verse::Alignment.new "\e[32mthe madness of men\e[0m"
|
95
|
+
alignment.align(22, :center)
|
96
|
+
# => " \e[32mthe madness of men\e[0m "
|
97
|
+
```
|
98
|
+
|
90
99
|
### 1.2 Pad
|
91
100
|
|
92
101
|
**Verse::Padding** provides facility to pad around text with a given padding.
|
@@ -178,6 +187,14 @@ truncation = Verse::Truncation.new 'ラドクリフ、マラソン五輪代表
|
|
178
187
|
truncation.truncate(12) # => "ラドクリフ…"
|
179
188
|
```
|
180
189
|
|
190
|
+
**Verse::Truncation** works with ANSI escape codoes:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
truncation = Verse::Trucnation.new "I try \e[34mall things\e[0m, I achieve what I can"
|
194
|
+
truncation.truncate(18)
|
195
|
+
# => "I try \e[34mall things\e[0m…"
|
196
|
+
```
|
197
|
+
|
181
198
|
### 1.5 Wrap
|
182
199
|
|
183
200
|
**Verse::Wrapping** allows you to wrap text into lines no longer than `wrap_at` argument length. The `wrap` method will break either on whitespace character or in case of east Asian characters on character boundaries.
|
@@ -210,6 +227,16 @@ wrapping.wrap(8) # =>
|
|
210
227
|
"にも含み"
|
211
228
|
```
|
212
229
|
|
230
|
+
**Verse::Wrapping** knows how to handle ANSI codes:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
wrapping = Verse::Wrapping.new "\e[32;44mIgnorance is the parent of fear.\e[0m"
|
234
|
+
wrapping.wrap(14) # =>
|
235
|
+
"\e[32;44mIgnorance is \e[0m"
|
236
|
+
"\e[32;44mthe parent of \e[0m"
|
237
|
+
"\e[32;44mfear.\e[0m"
|
238
|
+
```
|
239
|
+
|
213
240
|
You can also call `wrap` directly on **Verse**:
|
214
241
|
|
215
242
|
```ruby
|
data/lib/verse.rb
CHANGED
data/lib/verse/alignment.rb
CHANGED
@@ -12,8 +12,9 @@ module Verse
|
|
12
12
|
#
|
13
13
|
# @api public
|
14
14
|
def initialize(text, options = {})
|
15
|
-
@text
|
16
|
-
@
|
15
|
+
@text = text
|
16
|
+
@sanitizer = Sanitizer.new
|
17
|
+
@fill = options.fetch(:fill) { SPACE }
|
17
18
|
@direction = options.fetch(:direction) { :left }
|
18
19
|
end
|
19
20
|
|
@@ -103,7 +104,7 @@ module Verse
|
|
103
104
|
|
104
105
|
# @api private
|
105
106
|
def left_justify(text, width, filler)
|
106
|
-
width_diff = width -
|
107
|
+
width_diff = width - actual_width(text)
|
107
108
|
if width_diff > 0
|
108
109
|
text + filler * width_diff
|
109
110
|
else
|
@@ -113,7 +114,7 @@ module Verse
|
|
113
114
|
|
114
115
|
# @api private
|
115
116
|
def right_justify(text, width, filler)
|
116
|
-
width_diff = width -
|
117
|
+
width_diff = width - actual_width(text)
|
117
118
|
if width_diff > 0
|
118
119
|
filler * width_diff + text
|
119
120
|
else
|
@@ -123,7 +124,7 @@ module Verse
|
|
123
124
|
|
124
125
|
# @api private
|
125
126
|
def center_justify(text, width, filler)
|
126
|
-
text_width =
|
127
|
+
text_width = actual_width(text)
|
127
128
|
width_diff = width - text_width
|
128
129
|
if width_diff > 0
|
129
130
|
right_count = (width_diff.to_f / 2).ceil
|
@@ -134,6 +135,11 @@ module Verse
|
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
138
|
+
# @api private
|
139
|
+
def actual_width(text)
|
140
|
+
UnicodeUtils.display_width(@sanitizer.sanitize(text))
|
141
|
+
end
|
142
|
+
|
137
143
|
attr_reader :text
|
138
144
|
end # Alignment
|
139
145
|
end # Verse
|
data/lib/verse/padding.rb
CHANGED
@@ -7,8 +7,9 @@ module Verse
|
|
7
7
|
#
|
8
8
|
# @api public
|
9
9
|
def initialize(text, options = {})
|
10
|
-
@text
|
11
|
-
@padding
|
10
|
+
@text = text
|
11
|
+
@padding = Padder.parse(options[:padding])
|
12
|
+
@sanitizer = Sanitizer.new
|
12
13
|
end
|
13
14
|
|
14
15
|
# Pad content out
|
@@ -88,7 +89,7 @@ module Verse
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def display_width(string)
|
91
|
-
UnicodeUtils.display_width(string)
|
92
|
+
UnicodeUtils.display_width(@sanitizer.sanitize(string))
|
92
93
|
end
|
93
94
|
end # Padding
|
94
95
|
end # Verse
|
data/lib/verse/sanitizer.rb
CHANGED
@@ -17,6 +17,18 @@ module Verse
|
|
17
17
|
text.gsub(ANSI_MATCHER, '')
|
18
18
|
end
|
19
19
|
|
20
|
+
# Check if string is an ANSI code
|
21
|
+
#
|
22
|
+
# @param [String] string
|
23
|
+
# the string to check
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def ansi?(string)
|
29
|
+
!!(string =~ /^(\[)?\033(\[)?[;?\d]*[\dA-Za-z]([\];])?$/)
|
30
|
+
end
|
31
|
+
|
20
32
|
# Replace separator with whitespace
|
21
33
|
#
|
22
34
|
# @example
|
data/lib/verse/truncation.rb
CHANGED
@@ -22,7 +22,7 @@ module Verse
|
|
22
22
|
#
|
23
23
|
# @api public
|
24
24
|
def initialize(text, options = {})
|
25
|
-
@text = text
|
25
|
+
@text = text.dup.freeze
|
26
26
|
@sanitizer = Sanitizer.new
|
27
27
|
@separator = options.fetch(:separator) { nil }
|
28
28
|
@trailing = options.fetch(:trailing) { DEFAULT_TRAILING }
|
@@ -60,18 +60,20 @@ module Verse
|
|
60
60
|
if display_width(text) <= truncate_at.to_i || truncate_at.to_i.zero?
|
61
61
|
return text.dup
|
62
62
|
end
|
63
|
-
trail
|
64
|
-
separation
|
63
|
+
trail = options.fetch(:trailing) { trailing }
|
64
|
+
separation = options.fetch(:separator) { separator }
|
65
|
+
width = display_width(text)
|
65
66
|
sanitized_text = @sanitizer.sanitize(text)
|
66
|
-
width = display_width(sanitized_text)
|
67
67
|
|
68
68
|
return text if width <= truncate_at
|
69
69
|
|
70
70
|
length_without_trailing = truncate_at - display_width(trail)
|
71
|
-
chars =
|
71
|
+
chars = to_chars(sanitized_text).to_a
|
72
72
|
stop = chars[0, length_without_trailing].rindex(separation)
|
73
|
-
|
74
|
-
|
73
|
+
slice_length = stop || length_without_trailing
|
74
|
+
sliced_chars = chars[0, slice_length]
|
75
|
+
original_chars = to_chars(text).to_a[0, 3 * slice_length]
|
76
|
+
shorten(original_chars, sliced_chars, length_without_trailing).join + trail
|
75
77
|
end
|
76
78
|
|
77
79
|
protected
|
@@ -83,22 +85,34 @@ module Verse
|
|
83
85
|
# @return [String]
|
84
86
|
#
|
85
87
|
# @api private
|
86
|
-
def shorten(chars, length_without_trailing)
|
88
|
+
def shorten(original_chars, chars, length_without_trailing)
|
87
89
|
truncated = []
|
88
90
|
char_width = display_width(chars[0])
|
89
91
|
while length_without_trailing - char_width > 0
|
92
|
+
orig_char = original_chars.shift
|
90
93
|
char = chars.shift
|
91
94
|
break unless char
|
95
|
+
while orig_char != char # consume ansi
|
96
|
+
ansi = true
|
97
|
+
truncated << orig_char
|
98
|
+
orig_char = original_chars.shift
|
99
|
+
end
|
92
100
|
truncated << char
|
93
101
|
char_width = display_width(char)
|
94
102
|
length_without_trailing -= char_width
|
95
103
|
end
|
104
|
+
truncated << ["\e[0m"] if ansi
|
96
105
|
truncated
|
97
106
|
end
|
98
107
|
|
108
|
+
# @api private
|
109
|
+
def to_chars(text)
|
110
|
+
UnicodeUtils.each_grapheme(text).to_a
|
111
|
+
end
|
112
|
+
|
99
113
|
# @api private
|
100
114
|
def display_width(string)
|
101
|
-
UnicodeUtils.display_width(string)
|
115
|
+
UnicodeUtils.display_width(@sanitizer.sanitize(string))
|
102
116
|
end
|
103
117
|
end # Truncation
|
104
118
|
end # Verse
|
data/lib/verse/version.rb
CHANGED
data/lib/verse/wrapping.rb
CHANGED
@@ -43,11 +43,19 @@ module Verse
|
|
43
43
|
if text.length < wrap_at.to_i || wrap_at.to_i.zero?
|
44
44
|
return text
|
45
45
|
end
|
46
|
+
ansi_stack = []
|
46
47
|
text.split(NEWLINE, -1).map do |paragraph|
|
47
|
-
format_paragraph(paragraph, wrap_at)
|
48
|
+
format_paragraph(paragraph, wrap_at, ansi_stack)
|
48
49
|
end * NEWLINE
|
49
50
|
end
|
50
51
|
|
52
|
+
protected
|
53
|
+
|
54
|
+
# The text to wrap
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
attr_reader :text
|
58
|
+
|
51
59
|
# Format paragraph to be maximum of wrap_at length
|
52
60
|
#
|
53
61
|
# @param [String] paragraph
|
@@ -59,7 +67,7 @@ module Verse
|
|
59
67
|
# the wrapped lines
|
60
68
|
#
|
61
69
|
# @api private
|
62
|
-
def format_paragraph(paragraph, wrap_at)
|
70
|
+
def format_paragraph(paragraph, wrap_at, ansi_stack)
|
63
71
|
cleared_para = @sanitizer.replace(paragraph)
|
64
72
|
lines = []
|
65
73
|
line = ''
|
@@ -69,7 +77,25 @@ module Verse
|
|
69
77
|
char_length = 0 # visible char length
|
70
78
|
text_length = display_width(cleared_para)
|
71
79
|
total_length = 0
|
80
|
+
ansi = ''
|
81
|
+
matched = nil
|
72
82
|
UnicodeUtils.each_grapheme(cleared_para) do |char|
|
83
|
+
if char == ANSI # found ansi
|
84
|
+
ansi << char && next
|
85
|
+
end
|
86
|
+
|
87
|
+
if ansi.length > 0
|
88
|
+
ansi << char
|
89
|
+
if @sanitizer.ansi?(ansi) # we found ansi let's consume
|
90
|
+
matched = ansi
|
91
|
+
elsif matched
|
92
|
+
ansi_stack << [matched[0...-1], line_length + word_length]
|
93
|
+
matched = nil
|
94
|
+
ansi = ''
|
95
|
+
end
|
96
|
+
next if ansi.length > 0
|
97
|
+
end
|
98
|
+
|
73
99
|
char_length = display_width(char)
|
74
100
|
total_length += char_length
|
75
101
|
if line_length + word_length + char_length <= wrap_at
|
@@ -86,41 +112,72 @@ module Verse
|
|
86
112
|
end
|
87
113
|
|
88
114
|
if char == SPACE # ends with space
|
89
|
-
lines << line
|
115
|
+
lines << insert_ansi(ansi_stack, line)
|
90
116
|
line = ''
|
91
117
|
line_length = 0
|
92
|
-
word
|
93
|
-
word_length
|
118
|
+
word += char
|
119
|
+
word_length += char_length
|
94
120
|
elsif word_length + char_length <= wrap_at
|
95
|
-
lines << line
|
121
|
+
lines << insert_ansi(ansi_stack, line)
|
96
122
|
line = word + char
|
97
123
|
line_length = word_length + char_length
|
98
124
|
word = ''
|
99
125
|
word_length = 0
|
100
126
|
else # hyphenate word - too long to fit a line
|
101
|
-
lines << word
|
127
|
+
lines << insert_ansi(ansi_stack, word)
|
102
128
|
line_length = 0
|
103
129
|
word = char
|
104
130
|
word_length = char_length
|
105
131
|
end
|
106
132
|
end
|
107
|
-
lines << line unless line.empty?
|
108
|
-
lines << word unless word.empty?
|
133
|
+
lines << insert_ansi(ansi_stack, line) unless line.empty?
|
134
|
+
lines << insert_ansi(ansi_stack, word) unless word.empty?
|
109
135
|
lines
|
110
136
|
end
|
111
137
|
|
112
|
-
|
113
|
-
|
114
|
-
#
|
138
|
+
# Insert ANSI code into string
|
139
|
+
#
|
140
|
+
# Check if there are any ANSI states, if present
|
141
|
+
# insert ANSI codes at given positions unwinding the stack.
|
142
|
+
#
|
143
|
+
# @param [Array[Array[String, Integer]]] ansi_stack
|
144
|
+
# the ANSI codes to apply
|
145
|
+
#
|
146
|
+
# @param [String] string
|
147
|
+
# the string to insert ANSI codes into
|
148
|
+
#
|
149
|
+
# @return [String]
|
115
150
|
#
|
116
151
|
# @api private
|
117
|
-
|
152
|
+
def insert_ansi(ansi_stack, string)
|
153
|
+
return string if ansi_stack.empty?
|
154
|
+
to_remove = 0
|
155
|
+
reset_index = -1
|
156
|
+
output = string.dup
|
157
|
+
resetting = false
|
158
|
+
ansi_stack.reverse_each do |state|
|
159
|
+
if state[0] =~ /#{Regexp.quote(RESET)}/
|
160
|
+
resetting = true
|
161
|
+
reset_index = state[1]
|
162
|
+
to_remove += 2
|
163
|
+
next
|
164
|
+
elsif !resetting
|
165
|
+
reset_index = -1
|
166
|
+
resetting = false
|
167
|
+
end
|
168
|
+
|
169
|
+
color, color_index = *state
|
170
|
+
output.insert(reset_index, RESET).insert(color_index, color)
|
171
|
+
end
|
172
|
+
ansi_stack.pop(to_remove) # remove used states
|
173
|
+
output
|
174
|
+
end
|
118
175
|
|
119
176
|
# Visible width of string
|
120
177
|
#
|
121
178
|
# @api private
|
122
179
|
def display_width(string)
|
123
|
-
UnicodeUtils.display_width(string)
|
180
|
+
UnicodeUtils.display_width(@sanitizer.sanitize(string))
|
124
181
|
end
|
125
182
|
end # Wrapping
|
126
183
|
end # Verse
|
@@ -29,6 +29,12 @@ RSpec.describe Verse::Alignment, '.align' do
|
|
29
29
|
expect(alignment.center(20)).to eq(" こんにちは ")
|
30
30
|
end
|
31
31
|
|
32
|
+
it "centers ansi line" do
|
33
|
+
text = "\e[32mthe madness of men\e[0m"
|
34
|
+
alignment = Verse::Alignment.new(text)
|
35
|
+
expect(alignment.center(22)).to eq(" \e[32mthe madness of men\e[0m ")
|
36
|
+
end
|
37
|
+
|
32
38
|
it "centers multiline text" do
|
33
39
|
text = "for there is no folly of the beast\nof the earth which\nis not infinitely\noutdone by the madness of men"
|
34
40
|
alignment = Verse::Alignment.new(text)
|
@@ -51,6 +57,17 @@ RSpec.describe Verse::Alignment, '.align' do
|
|
51
57
|
].join)
|
52
58
|
end
|
53
59
|
|
60
|
+
it "centers ansi text" do
|
61
|
+
text = "for \e[35mthere\e[0m is no folly of the beast\nof the \e[33mearth\e0m which\nis \e[34mnot infinitely\e[0m\n\e[33moutdone\e[0m by the madness of men"
|
62
|
+
alignment = Verse::Alignment.new(text)
|
63
|
+
expect(alignment.center(40)).to eq([
|
64
|
+
" for \e[35mthere\e[0m is no folly of the beast \n",
|
65
|
+
" of the \e[33mearth\e0m which \n",
|
66
|
+
" is \e[34mnot infinitely\e[0m \n",
|
67
|
+
" \e[33moutdone\e[0m by the madness of men "
|
68
|
+
].join)
|
69
|
+
end
|
70
|
+
|
54
71
|
it "centers multiline text with fill of '*'" do
|
55
72
|
text = "for there is no folly of the beast\nof the earth which\nis not infinitely\noutdone by the madness of men"
|
56
73
|
alignment = Verse::Alignment.new(text, fill: '*')
|
@@ -20,6 +20,12 @@ RSpec.describe Verse::Alignment, '.left' do
|
|
20
20
|
expect(alignment.align(20, :left)).to eq("こんにちは ")
|
21
21
|
end
|
22
22
|
|
23
|
+
it "left justifies ansi line" do
|
24
|
+
text = "\e[32mthe madness of men\e[0m"
|
25
|
+
alignment = Verse::Alignment.new(text)
|
26
|
+
expect(alignment.align(22, :left)).to eq("\e[32mthe madness of men\e[0m ")
|
27
|
+
end
|
28
|
+
|
23
29
|
it "aligns multiline text to left" do
|
24
30
|
text = "for there is no folly of the beast\nof the earth which\nis not infinitely\noutdone by the madness of men"
|
25
31
|
alignment = Verse::Alignment.new(text)
|
@@ -42,7 +48,18 @@ RSpec.describe Verse::Alignment, '.left' do
|
|
42
48
|
].join)
|
43
49
|
end
|
44
50
|
|
45
|
-
it "
|
51
|
+
it "left justifies ansi text" do
|
52
|
+
text = "for \e[35mthere\e[0m is no folly of the beast\nof the \e[33mearth\e0m which\nis \e[34mnot infinitely\e[0m\n\e[33moutdone\e[0m by the madness of men"
|
53
|
+
alignment = Verse::Alignment.new(text)
|
54
|
+
expect(alignment.left(40)).to eq([
|
55
|
+
"for \e[35mthere\e[0m is no folly of the beast \n",
|
56
|
+
"of the \e[33mearth\e0m which \n",
|
57
|
+
"is \e[34mnot infinitely\e[0m \n",
|
58
|
+
"\e[33moutdone\e[0m by the madness of men "
|
59
|
+
].join)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "left justifies multiline text with fill of '*'" do
|
46
63
|
text = "for there is no folly of the beast\nof the earth which\nis not infinitely\noutdone by the madness of men"
|
47
64
|
alignment = Verse::Alignment.new(text, fill: '*')
|
48
65
|
expect(alignment.left(40)).to eq([
|
@@ -20,6 +20,12 @@ RSpec.describe Verse::Alignment, '.right' do
|
|
20
20
|
expect(alignment.align(20, :right)).to eq(" こんにちは")
|
21
21
|
end
|
22
22
|
|
23
|
+
it "right justifies utf line" do
|
24
|
+
text = "\e[32mthe madness of men\e[0m"
|
25
|
+
alignment = Verse::Alignment.new(text)
|
26
|
+
expect(alignment.align(22, :right)).to eq(" \e[32mthe madness of men\e[0m")
|
27
|
+
end
|
28
|
+
|
23
29
|
it "aligns multiline text to left" do
|
24
30
|
text = "for there is no folly of the beast\n of the earth which\n is not infinitely\n outdone by the madness of men"
|
25
31
|
alignment = Verse::Alignment.new(text)
|
@@ -42,7 +48,18 @@ RSpec.describe Verse::Alignment, '.right' do
|
|
42
48
|
].join)
|
43
49
|
end
|
44
50
|
|
45
|
-
it "
|
51
|
+
it "right justfies ansi text" do
|
52
|
+
text = "for \e[35mthere\e[0m is no folly of the beast\nof the \e[33mearth\e0m which\nis \e[34mnot infinitely\e[0m\n\e[33moutdone\e[0m by the madness of men"
|
53
|
+
alignment = Verse::Alignment.new(text)
|
54
|
+
expect(alignment.right(40)).to eq([
|
55
|
+
" for \e[35mthere\e[0m is no folly of the beast\n",
|
56
|
+
" of the \e[33mearth\e0m which\n",
|
57
|
+
" is \e[34mnot infinitely\e[0m\n",
|
58
|
+
" \e[33moutdone\e[0m by the madness of men"
|
59
|
+
].join)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "right justifies multiline text with fill of '*'" do
|
46
63
|
text = "for there is no folly of the beast\nof the earth which\nis not infinitely\noutdone by the madness of men"
|
47
64
|
alignment = Verse::Alignment.new(text, fill: '*')
|
48
65
|
expect(alignment.right(40)).to eq([
|
@@ -51,4 +51,17 @@ RSpec.describe Verse::Padding, '.pad' do
|
|
51
51
|
" ",
|
52
52
|
].join("\n"))
|
53
53
|
end
|
54
|
+
|
55
|
+
it "pads ANSI codes inside content" do
|
56
|
+
text = "It is \e[35mthe easiest\e[0m thing\nin the \e[34mworld\e[0m for a man\nto look as if he had \na great \e[33msecret\e[0m in him."
|
57
|
+
padding = Verse::Padding.new(text, padding: [1,1,1,1])
|
58
|
+
expect(padding.pad()).to eq([
|
59
|
+
" ",
|
60
|
+
" It is \e[35mthe easiest\e[0m thing ",
|
61
|
+
" in the \e[34mworld\e[0m for a man ",
|
62
|
+
" to look as if he had ",
|
63
|
+
" a great \e[33msecret\e[0m in him. ",
|
64
|
+
" ",
|
65
|
+
].join("\n"))
|
66
|
+
end
|
54
67
|
end
|
@@ -56,9 +56,9 @@ RSpec.describe Verse::Truncation, '.truncate' do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'correctly truncates with ANSI characters' do
|
59
|
-
text = "
|
59
|
+
text = "I try \e[34mall things\e[0m, I achieve what I can"
|
60
60
|
truncation = Verse::Truncation.new(text)
|
61
|
-
expect(truncation.truncate).to eq(
|
61
|
+
expect(truncation.truncate(18)).to eq("I try \e[34mall things\e[0m…")
|
62
62
|
end
|
63
63
|
|
64
64
|
it "finishes on word boundary" do
|
@@ -30,6 +30,21 @@ RSpec.describe Verse::Wrapping, '.wrap' do
|
|
30
30
|
].join("\n"))
|
31
31
|
end
|
32
32
|
|
33
|
+
it "preserves newlines" do
|
34
|
+
text = "It is not down\n on any map;\n true places never are."
|
35
|
+
wrapping = Verse::Wrapping.new(text)
|
36
|
+
expect(wrapping.wrap(10)).to eq([
|
37
|
+
"It is not ",
|
38
|
+
"down",
|
39
|
+
" on any ",
|
40
|
+
"map;",
|
41
|
+
" true ",
|
42
|
+
"places ",
|
43
|
+
"never are."
|
44
|
+
].join("\n"))
|
45
|
+
end
|
46
|
+
|
47
|
+
|
33
48
|
it "wraps ascii text" do
|
34
49
|
text = "for there is no folly of the beast of the earth which is not infinitely outdone by the madness of men "
|
35
50
|
wrapping = Verse::Wrapping.new(text)
|
@@ -100,4 +115,46 @@ RSpec.describe Verse::Wrapping, '.wrap' do
|
|
100
115
|
].join("\n"))
|
101
116
|
end
|
102
117
|
end
|
118
|
+
|
119
|
+
context 'with ANSI codes' do
|
120
|
+
it "wraps ANSI chars" do
|
121
|
+
text = "\e[32;44mIgnorance is the parent of fear.\e[0m"
|
122
|
+
wrapping = Verse::Wrapping.new(text)
|
123
|
+
expect(wrapping.wrap(14)).to eq([
|
124
|
+
"\e[32;44mIgnorance is \e[0m",
|
125
|
+
"\e[32;44mthe parent of \e[0m",
|
126
|
+
"\e[32;44mfear.\e[0m",
|
127
|
+
].join("\n"))
|
128
|
+
end
|
129
|
+
|
130
|
+
it "wraps ANSI in the middle of text" do
|
131
|
+
text = "Ignorance is the \e[32mparent\e[0m of fear."
|
132
|
+
wrapping = Verse::Wrapping.new(text)
|
133
|
+
expect(wrapping.wrap(14)).to eq([
|
134
|
+
"Ignorance is ",
|
135
|
+
"the \e[32mparent\e[0m of ",
|
136
|
+
"fear.",
|
137
|
+
].join("\n"))
|
138
|
+
end
|
139
|
+
|
140
|
+
it "wraps multline ANSI codes" do
|
141
|
+
text = "\e32;44mMulti\nLine\nContent.\e[0m"
|
142
|
+
wrapping = Verse::Wrapping.new(text)
|
143
|
+
expect(wrapping.wrap(14)).to eq([
|
144
|
+
"\e32;44mMulti\e[0m",
|
145
|
+
"\e32;44mLine\e[0m",
|
146
|
+
"\e32;44mContent.\e[0m",
|
147
|
+
].join("\n"))
|
148
|
+
end
|
149
|
+
|
150
|
+
it "wraps multiple ANSI codes in a single line" do
|
151
|
+
text = "Talk \e[32mnot\e[0m to me of \e[33mblasphemy\e[0m, man; I'd \e[35mstrike the sun\e[0m if it insulted me."
|
152
|
+
wrapping = Verse::Wrapping.new(text)
|
153
|
+
expect(wrapping.wrap(30)).to eq([
|
154
|
+
"Talk \e[32mnot\e[0m to me of \e[33mblasphemy\e[0m, ",
|
155
|
+
"man; I'd \e[35mstrike the sun\e[0m if it ",
|
156
|
+
"insulted me."
|
157
|
+
].join("\n"))
|
158
|
+
end
|
159
|
+
end
|
103
160
|
end
|
data/verse.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = [""]
|
11
11
|
spec.summary = %q{Text transformations such as truncation, wrapping, aligning, indentation and grouping of words.}
|
12
12
|
spec.description = %q{Text transformations such as truncation, wrapping, aligning, indentation and grouping of words.}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/peter-murach/verse"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: verse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: unicode_utils
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- spec/unit/padder/accessors_spec.rb
|
73
73
|
- spec/unit/padder/parse_spec.rb
|
74
74
|
- spec/unit/padding/pad_spec.rb
|
75
|
+
- spec/unit/sanitizer/ansi_spec.rb
|
75
76
|
- spec/unit/sanitizer/replace_spec.rb
|
76
77
|
- spec/unit/sanitizer/sanitize_spec.rb
|
77
78
|
- spec/unit/truncate_spec.rb
|
@@ -83,7 +84,7 @@ files:
|
|
83
84
|
- tasks/coverage.rake
|
84
85
|
- tasks/spec.rake
|
85
86
|
- verse.gemspec
|
86
|
-
homepage:
|
87
|
+
homepage: https://github.com/peter-murach/verse
|
87
88
|
licenses:
|
88
89
|
- MIT
|
89
90
|
metadata: {}
|
@@ -118,6 +119,7 @@ test_files:
|
|
118
119
|
- spec/unit/padder/accessors_spec.rb
|
119
120
|
- spec/unit/padder/parse_spec.rb
|
120
121
|
- spec/unit/padding/pad_spec.rb
|
122
|
+
- spec/unit/sanitizer/ansi_spec.rb
|
121
123
|
- spec/unit/sanitizer/replace_spec.rb
|
122
124
|
- spec/unit/sanitizer/sanitize_spec.rb
|
123
125
|
- spec/unit/truncate_spec.rb
|