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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7531f5a29482d44a943c00b361f49e6673bdd9c7
4
- data.tar.gz: 1bc1d1680d157e66faf7a44ba9c3ed0a804e7828
3
+ metadata.gz: 91a9c0b0722656e5b2b160a14e68f9d228830120
4
+ data.tar.gz: 9397441752523d44ac885b7e5ad4b0e8faffbead
5
5
  SHA512:
6
- metadata.gz: 5348385613bff73636e6b5993ebcafbba3ce1093a0b15e01c7c089248b61c09175c1793c0af5e8fdf482b2c149a0e9d6ea5b3d190c4246c689d5deba220b0d8a
7
- data.tar.gz: f1605d77c8ffaf24695739ca4df6bb646834b0ccfd3c2b3a51641cd0a48ab1729fafb57a079bc08a86522ace2f3c419991f1ee44c9826fbbcb1a2ea7899ce4f7
6
+ metadata.gz: aa1fb93fb455d0d141616c0a0dd08886486331a92b5b165a3ec1852f228b89e8002fb078d9329b0c9325a758725004ebb14f74c5ba618145de9c29990b2b0519
7
+ data.tar.gz: bf4deb4d61427c35aab5d4522b31003a49e1b93388e176fd19533dfe3177e618126beee94893de210b14f64b5c51555b707cb7b39b1d17dd168ead985af54c6d
@@ -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
@@ -15,6 +15,8 @@ module Verse
15
15
  SPACE = ' '.freeze
16
16
  NEWLINE = "\n".freeze
17
17
  TAB = "\n".freeze
18
+ RESET = "\e[0m".freeze
19
+ ANSI = "\033".freeze
18
20
 
19
21
  SPACE_RE = %r{\s+}mo.freeze
20
22
  NEWLINE_RE = %r{\n}o.freeze
@@ -12,8 +12,9 @@ module Verse
12
12
  #
13
13
  # @api public
14
14
  def initialize(text, options = {})
15
- @text = text
16
- @fill = options.fetch(:fill) { SPACE }
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 - UnicodeUtils.display_width(text)
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 - UnicodeUtils.display_width(text)
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 = UnicodeUtils.display_width(text)
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
@@ -7,8 +7,9 @@ module Verse
7
7
  #
8
8
  # @api public
9
9
  def initialize(text, options = {})
10
- @text = text
11
- @padding = Padder.parse(options[: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
@@ -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
@@ -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 = options.fetch(:trailing) { trailing }
64
- separation = options.fetch(:separator) { separator }
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 = UnicodeUtils.each_grapheme(sanitized_text).to_a
71
+ chars = to_chars(sanitized_text).to_a
72
72
  stop = chars[0, length_without_trailing].rindex(separation)
73
- sliced_chars = chars[0, stop || length_without_trailing]
74
- shorten(sliced_chars, length_without_trailing).join + trail
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
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Verse
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end # Verse
@@ -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 = word + char
93
- word_length = word_length + char_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
- protected
113
-
114
- # The text to wrap
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
- attr_reader :text
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 "centers multiline text with fill of '*'" do
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 "centers multiline text with fill of '*'" do
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
@@ -0,0 +1,11 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Verse::Sanitizer, '.ansi?' do
6
+ subject(:sanitizer) { described_class.new }
7
+
8
+ it "checks if code is ansi" do
9
+ expect(sanitizer.ansi?("\e[0;33m")).to eq(true)
10
+ end
11
+ 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 = "This is a \e[1m\e[34mbold blue text\e[0m"
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(text)
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
@@ -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.3.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-02-28 00:00:00.000000000 Z
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