terminal-layout 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -1
- data/lib/terminal_layout/version.rb +1 -1
- data/lib/terminal_layout.rb +1 -1
- data/terminal-layout.gemspec +1 -0
- metadata +16 -5
- data/lib/ansi_string.rb +0 -371
- data/spec/ansi_string_spec.rb +0 -701
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97802dee983f8248f8d8406cf323754b8768613a
|
4
|
+
data.tar.gz: 7af99e4ca121f6cf67668985954e2f52bb26aa87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5698f4d780074e3b2d10540a7dbbb27f7d0f6046ac93826ca86be379aa43266c997826b5723c0605788bc9b67080c9f4715cc647dd021d2f35e4eef8a08762e7
|
7
|
+
data.tar.gz: cf51538f560efbd170bb726cef284adebbede5599ae418f626f011447a2fcbadefe745c501c0a8187770c1104c344f2907238ff70ecfab5a19043e3d4fcd687e
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
terminal-layout (0.4.
|
4
|
+
terminal-layout (0.4.1)
|
5
|
+
ansi_string (~> 0.1)
|
5
6
|
highline (~> 1.7, >= 1.7.8)
|
6
7
|
ruby-terminfo (~> 0.1.1)
|
7
8
|
ruby-termios (~> 0.9.6)
|
@@ -10,6 +11,7 @@ PATH
|
|
10
11
|
GEM
|
11
12
|
remote: https://rubygems.org/
|
12
13
|
specs:
|
14
|
+
ansi_string (0.1.0)
|
13
15
|
byebug (5.0.0)
|
14
16
|
columnize (= 0.9.0)
|
15
17
|
coderay (1.1.0)
|
data/lib/terminal_layout.rb
CHANGED
data/terminal-layout.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency 'ansi_string', '~> 0.1'
|
21
22
|
spec.add_dependency "ruby-terminfo", "~> 0.1.1"
|
22
23
|
spec.add_dependency "ruby-termios", "~> 0.9.6"
|
23
24
|
spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8'
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal-layout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ansi_string
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.1'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: ruby-terminfo
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,11 +143,9 @@ files:
|
|
129
143
|
- README.md
|
130
144
|
- Rakefile
|
131
145
|
- block-flow.rb
|
132
|
-
- lib/ansi_string.rb
|
133
146
|
- lib/tasks/gem.rake
|
134
147
|
- lib/terminal_layout.rb
|
135
148
|
- lib/terminal_layout/version.rb
|
136
|
-
- spec/ansi_string_spec.rb
|
137
149
|
- spec/spec_helper.rb
|
138
150
|
- spec/terminal_layout_spec.rb
|
139
151
|
- terminal-layout.gemspec
|
@@ -163,7 +175,6 @@ signing_key:
|
|
163
175
|
specification_version: 4
|
164
176
|
summary: A terminal layout manager
|
165
177
|
test_files:
|
166
|
-
- spec/ansi_string_spec.rb
|
167
178
|
- spec/spec_helper.rb
|
168
179
|
- spec/terminal_layout_spec.rb
|
169
180
|
has_rdoc:
|
data/lib/ansi_string.rb
DELETED
@@ -1,371 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
|
-
class ANSIString
|
6
|
-
extend Forwardable
|
7
|
-
attr_reader :raw, :without_ansi
|
8
|
-
|
9
|
-
def_delegators :@without_ansi, :each_char, :each_byte, :index,
|
10
|
-
:match, :=~
|
11
|
-
|
12
|
-
def initialize(str)
|
13
|
-
process_string raw_string_for(str)
|
14
|
-
end
|
15
|
-
|
16
|
-
def +(other)
|
17
|
-
self.class.new @raw + raw_string_for(other)
|
18
|
-
end
|
19
|
-
|
20
|
-
def <<(other)
|
21
|
-
range = length..length
|
22
|
-
str = replace_in_string(range, other)
|
23
|
-
process_string raw_string_for(str)
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def insert(position, string)
|
28
|
-
if position < 0
|
29
|
-
position = @without_ansi.length + position + 1
|
30
|
-
end
|
31
|
-
self[position...position] = string
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def empty?
|
36
|
-
length == 0
|
37
|
-
end
|
38
|
-
|
39
|
-
def [](range)
|
40
|
-
# convert numeric position to a range
|
41
|
-
range = (range..range) if range.is_a?(Integer)
|
42
|
-
|
43
|
-
range_begin = range.begin
|
44
|
-
range_end = range.end
|
45
|
-
|
46
|
-
if range.exclude_end?
|
47
|
-
if range_begin == 0 && range_end == 0
|
48
|
-
return ""
|
49
|
-
else
|
50
|
-
range_end -= 1
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
range_begin = @without_ansi.length - range.begin.abs if range.begin < 0
|
55
|
-
range_end = @without_ansi.length - range.end.abs if range.end < 0
|
56
|
-
|
57
|
-
str = build_string_with_ansi_for(range_begin..range_end)
|
58
|
-
ANSIString.new str if str
|
59
|
-
end
|
60
|
-
|
61
|
-
def []=(range, replacement_str)
|
62
|
-
# convert numeric position to a range
|
63
|
-
range = (range..range) if range.is_a?(Integer)
|
64
|
-
|
65
|
-
range_begin = range.begin
|
66
|
-
range_end = range.exclude_end? ? range.end - 1 : range.end
|
67
|
-
|
68
|
-
range_begin = @without_ansi.length - range.begin.abs if range.begin < 0
|
69
|
-
range_end = @without_ansi.length - range.end.abs if range.end < 0
|
70
|
-
|
71
|
-
updated_string = replace_in_string(range_begin..range_end, replacement_str)
|
72
|
-
process_string raw_string_for(updated_string)
|
73
|
-
self
|
74
|
-
end
|
75
|
-
|
76
|
-
# See String#rindex for arguments
|
77
|
-
def rindex(*args)
|
78
|
-
@without_ansi.rindex(*args)
|
79
|
-
end
|
80
|
-
|
81
|
-
def replace(str)
|
82
|
-
process_string raw_string_for(str)
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def reverse
|
87
|
-
str = @ansi_sequence_locations.reverse.map do |location|
|
88
|
-
[location[:start_ansi_sequence], location[:text].reverse, location[:end_ansi_sequence]].join
|
89
|
-
end.join
|
90
|
-
ANSIString.new str
|
91
|
-
end
|
92
|
-
|
93
|
-
def scan(pattern)
|
94
|
-
results = []
|
95
|
-
without_ansi.enum_for(:scan, pattern).each do
|
96
|
-
md = Regexp.last_match
|
97
|
-
if md.captures.any?
|
98
|
-
results << md.captures.map.with_index do |_, i|
|
99
|
-
# captures use 1-based indexing
|
100
|
-
self[md.begin(i+1)..md.end(i+1)-1]
|
101
|
-
end
|
102
|
-
else
|
103
|
-
results << self[md.begin(0)..md.end(0)-1]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
results
|
107
|
-
end
|
108
|
-
|
109
|
-
def slice(index, length=nil)
|
110
|
-
return ANSIString.new("") if length == 0
|
111
|
-
range = nil
|
112
|
-
index = index.without_ansi if index.is_a?(ANSIString)
|
113
|
-
index = Regexp.new Regexp.escape(index) if index.is_a?(String)
|
114
|
-
if index.is_a?(Integer)
|
115
|
-
length ||= 1
|
116
|
-
range = (index..index+length-1)
|
117
|
-
elsif index.is_a?(Range)
|
118
|
-
range = index
|
119
|
-
elsif index.is_a?(Regexp)
|
120
|
-
md = @without_ansi.match(index)
|
121
|
-
capture_group_index = length || 0
|
122
|
-
if md
|
123
|
-
capture_group = md.offset(capture_group_index)
|
124
|
-
range = (capture_group.first..capture_group.last-1)
|
125
|
-
end
|
126
|
-
else
|
127
|
-
raise(ArgumentError, "Must pass in at least an index or a range.")
|
128
|
-
end
|
129
|
-
self[range] if range
|
130
|
-
end
|
131
|
-
|
132
|
-
def split(*args)
|
133
|
-
raw.split(*args).map { |s| ANSIString.new(s) }
|
134
|
-
end
|
135
|
-
|
136
|
-
def strip
|
137
|
-
ANSIString.new raw.strip
|
138
|
-
end
|
139
|
-
|
140
|
-
def length
|
141
|
-
@without_ansi.length
|
142
|
-
end
|
143
|
-
|
144
|
-
def lines
|
145
|
-
result = []
|
146
|
-
current_string = ""
|
147
|
-
@ansi_sequence_locations.map do |location|
|
148
|
-
if location[:text] == "\n"
|
149
|
-
result << ANSIString.new(current_string + "\n")
|
150
|
-
current_string = ""
|
151
|
-
next
|
152
|
-
end
|
153
|
-
|
154
|
-
location[:text].scan(/.*(?:\n|$)/).each_with_index do |line, i|
|
155
|
-
break if line == ""
|
156
|
-
|
157
|
-
if i == 0
|
158
|
-
current_string << [
|
159
|
-
location[:start_ansi_sequence],
|
160
|
-
line,
|
161
|
-
location[:end_ansi_sequence]
|
162
|
-
].join
|
163
|
-
else
|
164
|
-
result << ANSIString.new(current_string)
|
165
|
-
current_string = ""
|
166
|
-
current_string << [
|
167
|
-
location[:start_ansi_sequence],
|
168
|
-
line,
|
169
|
-
location[:end_ansi_sequence]
|
170
|
-
].join
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
if location[:text].end_with?("\n")
|
175
|
-
result << ANSIString.new(current_string)
|
176
|
-
current_string = ""
|
177
|
-
next
|
178
|
-
end
|
179
|
-
end
|
180
|
-
result << ANSIString.new(current_string) if current_string.length > 0
|
181
|
-
result
|
182
|
-
end
|
183
|
-
|
184
|
-
def dup
|
185
|
-
ANSIString.new(@raw.dup)
|
186
|
-
end
|
187
|
-
|
188
|
-
def sub(pattern, replacement)
|
189
|
-
str = ""
|
190
|
-
count = 0
|
191
|
-
max_count = 1
|
192
|
-
index = 0
|
193
|
-
@without_ansi.enum_for(:scan, pattern).each do
|
194
|
-
md = Regexp.last_match
|
195
|
-
str << build_string_with_ansi_for(index...(index + md.begin(0)))
|
196
|
-
index = md.end(0)
|
197
|
-
break if (count += 1) == max_count
|
198
|
-
end
|
199
|
-
if index != @without_ansi.length
|
200
|
-
str << build_string_with_ansi_for(index..@without_ansi.length)
|
201
|
-
end
|
202
|
-
nstr = str.gsub /(\033\[[0-9;]*m)(.+?)\033\[0m\1/, '\1\2'
|
203
|
-
ANSIString.new(nstr)
|
204
|
-
end
|
205
|
-
|
206
|
-
def to_s
|
207
|
-
@raw.dup
|
208
|
-
end
|
209
|
-
alias :to_str :to_s
|
210
|
-
|
211
|
-
def inspect
|
212
|
-
to_s.inspect
|
213
|
-
end
|
214
|
-
|
215
|
-
def ==(other)
|
216
|
-
(other.class == self.class && other.raw == @raw) || (other.kind_of?(String) && other == @raw)
|
217
|
-
end
|
218
|
-
|
219
|
-
def <=>(other)
|
220
|
-
(other.class == self.class && @raw <=> other.raw)
|
221
|
-
end
|
222
|
-
|
223
|
-
private
|
224
|
-
|
225
|
-
def raw_string_for(str)
|
226
|
-
str.is_a?(ANSIString) ? str.raw : str.to_s
|
227
|
-
end
|
228
|
-
|
229
|
-
def process_string(raw_str)
|
230
|
-
@without_ansi = ""
|
231
|
-
@ansi_sequence_locations = []
|
232
|
-
raw_str.enum_for(:scan, /(\e\[[0-9;]*m)?(.*?)(?=\e\[[0-9;]*m|\Z)/m ).each do
|
233
|
-
md = Regexp.last_match
|
234
|
-
ansi_sequence, text = md.captures
|
235
|
-
|
236
|
-
previous_sequence_location = @ansi_sequence_locations.last
|
237
|
-
if previous_sequence_location
|
238
|
-
if ansi_sequence == "\e[0m"
|
239
|
-
previous_sequence_location[:end_ansi_sequence] = ansi_sequence
|
240
|
-
ansi_sequence = nil
|
241
|
-
elsif previous_sequence_location[:start_ansi_sequence] == ansi_sequence
|
242
|
-
previous_sequence_location[:text] << text
|
243
|
-
previous_sequence_location[:ends_at] += text.length
|
244
|
-
previous_sequence_location[:length] += text.length
|
245
|
-
@without_ansi << text
|
246
|
-
next
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
if ansi_sequence.nil? && text.to_s.length == 0
|
251
|
-
next
|
252
|
-
end
|
253
|
-
|
254
|
-
@ansi_sequence_locations.push(
|
255
|
-
begins_at: @without_ansi.length,
|
256
|
-
ends_at: [@without_ansi.length + text.length - 1, 0].max,
|
257
|
-
length: text.length,
|
258
|
-
text: text,
|
259
|
-
start_ansi_sequence: ansi_sequence
|
260
|
-
)
|
261
|
-
|
262
|
-
@without_ansi << text
|
263
|
-
end
|
264
|
-
|
265
|
-
@raw = @ansi_sequence_locations.map do |location|
|
266
|
-
[location[:start_ansi_sequence], location[:text], location[:end_ansi_sequence]].compact.join
|
267
|
-
end.join
|
268
|
-
|
269
|
-
@ansi_sequence_locations
|
270
|
-
end
|
271
|
-
|
272
|
-
def replace_in_string(range, replacement_str)
|
273
|
-
raise RangeError, "#{range.inspect} out of range" if range.begin > length
|
274
|
-
return replacement_str if @ansi_sequence_locations.empty?
|
275
|
-
|
276
|
-
range = range.begin..(range.end - 1) if range.exclude_end?
|
277
|
-
str = ""
|
278
|
-
@ansi_sequence_locations.each_with_index do |location, j|
|
279
|
-
# If the given range encompasses part of the location, then we want to
|
280
|
-
# include the whole location
|
281
|
-
if location[:begins_at] >= range.begin && location[:ends_at] <= range.end
|
282
|
-
end_index = range.end - location[:begins_at] + 1
|
283
|
-
|
284
|
-
str << [
|
285
|
-
location[:start_ansi_sequence],
|
286
|
-
replacement_str,
|
287
|
-
location[:text][end_index..-1],
|
288
|
-
location[:end_ansi_sequence]
|
289
|
-
].join
|
290
|
-
|
291
|
-
# If the location falls within the given range then make sure we pull
|
292
|
-
# out the bits that we want, and keep ANSI escape sequenece intact while
|
293
|
-
# doing so.
|
294
|
-
elsif location[:begins_at] <= range.begin && location[:ends_at] >= range.end
|
295
|
-
start_index = range.begin - location[:begins_at]
|
296
|
-
end_index = range.end - location[:begins_at] + 1
|
297
|
-
|
298
|
-
str << [
|
299
|
-
location[:start_ansi_sequence],
|
300
|
-
location[:text][0...start_index],
|
301
|
-
replacement_str,
|
302
|
-
location[:text][end_index..-1],
|
303
|
-
location[:end_ansi_sequence]
|
304
|
-
].join
|
305
|
-
|
306
|
-
elsif location[:ends_at] == range.begin
|
307
|
-
start_index = range.begin - location[:begins_at]
|
308
|
-
end_index = range.end
|
309
|
-
num_chars_to_remove_from_next_location = range.end - location[:ends_at]
|
310
|
-
|
311
|
-
str << [
|
312
|
-
location[:start_ansi_sequence],
|
313
|
-
location[:text][location[:begins_at]...(location[:begins_at]+start_index)],
|
314
|
-
replacement_str,
|
315
|
-
location[:text][end_index..-1],
|
316
|
-
location[:end_ansi_sequence],
|
317
|
-
].join
|
318
|
-
|
319
|
-
if location=@ansi_sequence_locations[j+1]
|
320
|
-
old = location.dup
|
321
|
-
location[:text][0...num_chars_to_remove_from_next_location] = ""
|
322
|
-
location[:begins_at] += num_chars_to_remove_from_next_location
|
323
|
-
location[:ends_at] += num_chars_to_remove_from_next_location
|
324
|
-
end
|
325
|
-
|
326
|
-
# If we're pushing onto the end of the string
|
327
|
-
elsif range.begin == length && location[:ends_at] == length - 1
|
328
|
-
if replacement_str.is_a?(ANSIString)
|
329
|
-
str << [location[:start_ansi_sequence], location[:text], location[:end_ansi_sequence], replacement_str].join
|
330
|
-
else
|
331
|
-
str << [location[:start_ansi_sequence], location[:text], replacement_str, location[:end_ansi_sequence]].join
|
332
|
-
end
|
333
|
-
else
|
334
|
-
str << [location[:start_ansi_sequence], location[:text], location[:end_ansi_sequence]].join
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
str
|
339
|
-
end
|
340
|
-
|
341
|
-
def build_string_with_ansi_for(range)
|
342
|
-
return nil if range.begin > length
|
343
|
-
|
344
|
-
str = ""
|
345
|
-
|
346
|
-
if range.exclude_end?
|
347
|
-
range = range.begin..(range.end - 1)
|
348
|
-
end
|
349
|
-
|
350
|
-
@ansi_sequence_locations.each do |location|
|
351
|
-
# If the given range encompasses part of the location, then we want to
|
352
|
-
# include the whole location
|
353
|
-
if location[:begins_at] >= range.begin && location[:ends_at] <= range.end
|
354
|
-
str << [location[:start_ansi_sequence], location[:text], location[:end_ansi_sequence]].join
|
355
|
-
|
356
|
-
elsif location[:begins_at] >= range.begin && location[:begins_at] <= range.end
|
357
|
-
str << [location[:start_ansi_sequence], location[:text][0..(range.end - location[:begins_at])], location[:end_ansi_sequence]].join
|
358
|
-
|
359
|
-
# If the location falls within the given range then make sure we pull
|
360
|
-
# out the bits that we want, and keep ANSI escape sequenece intact while
|
361
|
-
# doing so.
|
362
|
-
elsif (location[:begins_at] <= range.begin && location[:ends_at] >= range.end) || range.cover?(location[:ends_at])
|
363
|
-
start_index = range.begin - location[:begins_at]
|
364
|
-
end_index = range.end - location[:begins_at]
|
365
|
-
str << [location[:start_ansi_sequence], location[:text][start_index..end_index], location[:end_ansi_sequence]].join
|
366
|
-
end
|
367
|
-
end
|
368
|
-
str
|
369
|
-
end
|
370
|
-
|
371
|
-
end
|
data/spec/ansi_string_spec.rb
DELETED
@@ -1,701 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'term/ansicolor'
|
3
|
-
|
4
|
-
describe 'ANSIString' do
|
5
|
-
include Term::ANSIColor
|
6
|
-
|
7
|
-
describe "constructing" do
|
8
|
-
it "can be constructed with a String" do
|
9
|
-
ansi_string = ANSIString.new "this is a string"
|
10
|
-
expect(ansi_string).to be
|
11
|
-
end
|
12
|
-
|
13
|
-
it "can be constructed with a String containing ANSI escape sequences" do
|
14
|
-
ansi_string = ANSIString.new "this #{blue('is')} a string"
|
15
|
-
expect(ansi_string).to be
|
16
|
-
end
|
17
|
-
|
18
|
-
it "can be constructed with UTF-8 characters" do;
|
19
|
-
expect do
|
20
|
-
ansi_string = ANSIString.new "this #{blue('ƒ')} a string"
|
21
|
-
expect(ansi_string).to be
|
22
|
-
end.to_not raise_error
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe "redundant ANSI sequences" do
|
27
|
-
it "strips out redundant ANSI sequences that are immediately next to each other" do
|
28
|
-
ansi_string = ANSIString.new "this is\e[31m\e[31m a string"
|
29
|
-
expect(ansi_string.to_s).to eq "this is\e[31m a string"
|
30
|
-
end
|
31
|
-
|
32
|
-
it "strips out redundant ANSI sequences that are not immediately next to each other" do
|
33
|
-
ansi_string = ANSIString.new "this \e[31m a\e[31m string"
|
34
|
-
expect(ansi_string.to_s).to eq "this \e[31m a string"
|
35
|
-
end
|
36
|
-
|
37
|
-
it "does not strip out ANSI sequences that differ" do
|
38
|
-
ansi_string = ANSIString.new "this \e[31m a\e[32m string"
|
39
|
-
expect(ansi_string.to_s).to eq "this \e[31m a\e[32m string"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe "#+ combining strings" do
|
44
|
-
let(:blue_ansi_string){ ANSIString.new blue_string }
|
45
|
-
let(:yellow_ansi_string){ ANSIString.new yellow_string }
|
46
|
-
let(:blue_string){ blue("this is blue") }
|
47
|
-
let(:yellow_string){ yellow("this is yellow") }
|
48
|
-
|
49
|
-
it "returns a new string when combining two ANSIStrings" do
|
50
|
-
expect(blue_ansi_string + yellow_ansi_string).to eq ANSIString.new(blue_string + yellow_string)
|
51
|
-
end
|
52
|
-
|
53
|
-
it "returns a new string when combining a ANIString with a String" do
|
54
|
-
expect(blue_ansi_string + yellow_string).to eq ANSIString.new(blue_string + yellow_string)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe "#each_byte" do
|
59
|
-
let(:blue_ansi_string){ ANSIString.new blue_string }
|
60
|
-
let(:blue_string){ blue("this is blue") }
|
61
|
-
|
62
|
-
it "iterates over each character ignoring ANSI sequences" do
|
63
|
-
expected = "this is blue"
|
64
|
-
actual = ""
|
65
|
-
blue_ansi_string.each_byte { |ch| actual << ch }
|
66
|
-
expect(actual).to eq(expected)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "#each_char" do
|
71
|
-
let(:blue_ansi_string){ ANSIString.new blue_string }
|
72
|
-
let(:blue_string){ blue("this is blue") }
|
73
|
-
|
74
|
-
it "iterates over each character ignoring ANSI sequences" do
|
75
|
-
expected = "this is blue"
|
76
|
-
actual = ""
|
77
|
-
blue_ansi_string.each_char { |ch| actual << ch }
|
78
|
-
expect(actual).to eq(expected)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
describe "#<<" do
|
83
|
-
it "appends a String onto the end of the current ANSIString" do
|
84
|
-
ansi_string = ANSIString.new ""
|
85
|
-
ansi_string << "a"
|
86
|
-
expect(ansi_string).to eq ANSIString.new("a")
|
87
|
-
|
88
|
-
ansi_string << "b"
|
89
|
-
expect(ansi_string).to eq ANSIString.new("ab")
|
90
|
-
|
91
|
-
ansi_string << "cd"
|
92
|
-
expect(ansi_string).to eq ANSIString.new("abcd")
|
93
|
-
end
|
94
|
-
|
95
|
-
it "appends an ANSIString onto the end of the current ANSIString" do
|
96
|
-
ansi_string = ANSIString.new ""
|
97
|
-
ansi_string << ANSIString.new(blue("a"))
|
98
|
-
expect(ansi_string).to eq ANSIString.new("#{blue('a')}")
|
99
|
-
|
100
|
-
ansi_string << ANSIString.new(yellow("b"))
|
101
|
-
expect(ansi_string).to eq ANSIString.new("#{blue('a')}#{yellow('b')}")
|
102
|
-
|
103
|
-
ansi_string << ANSIString.new(red("cd"))
|
104
|
-
expect(ansi_string).to eq ANSIString.new("#{blue('a')}#{yellow('b')}#{red('cd')}")
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "#insert (see Ruby's String#insert for intent)" do
|
109
|
-
it "insert a string into the ANSIString" do
|
110
|
-
ansi_string = ANSIString.new "az"
|
111
|
-
ansi_string.insert 1, "thru"
|
112
|
-
expect(ansi_string).to eq ANSIString.new("athruz")
|
113
|
-
|
114
|
-
ansi_string.insert 0, "_"
|
115
|
-
expect(ansi_string).to eq ANSIString.new("_athruz")
|
116
|
-
|
117
|
-
ansi_string.insert ansi_string.length, "_"
|
118
|
-
expect(ansi_string).to eq ANSIString.new("_athruz_")
|
119
|
-
end
|
120
|
-
|
121
|
-
it "insert an ANSIString into an ANSIString" do
|
122
|
-
ansi_string = ANSIString.new blue("az")
|
123
|
-
ansi_string.insert 1, yellow("thru")
|
124
|
-
expect(ansi_string).to eq ANSIString.new("\e[34ma\e[33mthru\e[0mz\e[0m")
|
125
|
-
end
|
126
|
-
|
127
|
-
it "inserts from the end with a negative position" do
|
128
|
-
ansi_string = ANSIString.new blue("az")
|
129
|
-
ansi_string.insert -2, yellow("thru")
|
130
|
-
expect(ansi_string).to eq ANSIString.new("\e[34ma\e[33mthru\e[0mz\e[0m")
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
describe "#length" do
|
135
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
136
|
-
let(:string){ "this is blue" }
|
137
|
-
|
138
|
-
it "returns the length string without ANSI escape sequences" do
|
139
|
-
expect(ansi_string.length).to eq string.length
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe "#empty?" do
|
144
|
-
it "returns true when empty" do
|
145
|
-
expect(ANSIString.new("").empty?).to be(true)
|
146
|
-
end
|
147
|
-
|
148
|
-
it "returns true when it only contains ANSI sequences" do
|
149
|
-
expect(ANSIString.new(blue("")).empty?).to be(true)
|
150
|
-
end
|
151
|
-
|
152
|
-
it "returns false when there are non-ANSI characters" do
|
153
|
-
expect(ANSIString.new("a").empty?).to be(false)
|
154
|
-
expect(ANSIString.new(blue("a")).empty?).to be(false)
|
155
|
-
end
|
156
|
-
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "#index" do
|
160
|
-
it "returns the index of the first occurrence of the given substring" do
|
161
|
-
ansi_string = ANSIString.new("this is not blue")
|
162
|
-
expect(ansi_string.index("b")).to eq 12
|
163
|
-
|
164
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
165
|
-
expect(ansi_string.index("blu")).to eq 8
|
166
|
-
|
167
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
168
|
-
expect(ansi_string.index("yellow")).to eq 25
|
169
|
-
end
|
170
|
-
|
171
|
-
it "returns the index starting on or after an optional start position" do
|
172
|
-
ansi_string = ANSIString.new("this is not blue")
|
173
|
-
expect(ansi_string.index("t", 0)).to eq 0
|
174
|
-
|
175
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
176
|
-
expect(ansi_string.index("is", 3)).to eq 5
|
177
|
-
expect(ansi_string.index("bl", 7)).to eq 8
|
178
|
-
expect(ansi_string.index("bl", 9)).to eq nil
|
179
|
-
|
180
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
181
|
-
expect(ansi_string.index("yel", 5)).to eq 25
|
182
|
-
expect(ansi_string.index("yel", 25)).to eq 25
|
183
|
-
expect(ansi_string.index("yel", 26)).to eq nil
|
184
|
-
end
|
185
|
-
|
186
|
-
it "returns the index of the first occurrence of the given regular expression" do
|
187
|
-
ansi_string = ANSIString.new("this is not blue")
|
188
|
-
expect(ansi_string.index(/b/)).to eq 12
|
189
|
-
|
190
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
191
|
-
expect(ansi_string.index(/blu/)).to eq 8
|
192
|
-
|
193
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
194
|
-
expect(ansi_string.index(/y.ll.w/)).to eq 25
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe "#rindex" do
|
199
|
-
it "returns the index of the last occurrence of the given substring" do
|
200
|
-
ansi_string = ANSIString.new("this is not blue")
|
201
|
-
expect(ansi_string.rindex("i")).to eq 5
|
202
|
-
|
203
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
204
|
-
expect(ansi_string.rindex("blu")).to eq 8
|
205
|
-
|
206
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
207
|
-
expect(ansi_string.rindex("yellow")).to eq 25
|
208
|
-
end
|
209
|
-
|
210
|
-
it "returns the index of the match on or after an optional stop position" do
|
211
|
-
ansi_string = ANSIString.new("this is not blue")
|
212
|
-
expect(ansi_string.rindex("t", 0)).to eq 0
|
213
|
-
expect(ansi_string.rindex("is", 3)).to eq 2
|
214
|
-
expect(ansi_string.rindex("bl", 12)).to eq 12
|
215
|
-
|
216
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
217
|
-
expect(ansi_string.rindex("is", 0)).to eq nil
|
218
|
-
expect(ansi_string.rindex("is", 3)).to eq 2
|
219
|
-
expect(ansi_string.rindex("bl", 8)).to eq 8
|
220
|
-
expect(ansi_string.rindex("bl", 12)).to eq 8
|
221
|
-
|
222
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
223
|
-
expect(ansi_string.rindex("yel", 5)).to eq nil
|
224
|
-
expect(ansi_string.rindex("yel", 25)).to eq 25
|
225
|
-
expect(ansi_string.rindex("yel", 26)).to eq 25
|
226
|
-
end
|
227
|
-
|
228
|
-
it "returns the index of the last occurrence of the given regular expression" do
|
229
|
-
ansi_string = ANSIString.new("this is not blue")
|
230
|
-
expect(ansi_string.rindex(/b/)).to eq 12
|
231
|
-
|
232
|
-
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
233
|
-
expect(ansi_string.rindex(/blu/)).to eq 8
|
234
|
-
|
235
|
-
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
236
|
-
expect(ansi_string.rindex(/y.ll.w/)).to eq 25
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
describe "#[]" do
|
241
|
-
subject(:ansi_string){ ANSIString.new "#{blue_string}ABC#{yellow_string}" }
|
242
|
-
let(:blue_string){ blue("this is blue") }
|
243
|
-
let(:yellow_string){ yellow("this is yellow") }
|
244
|
-
|
245
|
-
it "returns the full substring with the appropriate ANSI start and end sequence" do
|
246
|
-
expect(ansi_string[0...12]).to eq ANSIString.new(blue("this is blue"))
|
247
|
-
expect(ansi_string[15..-1]).to eq ANSIString.new(yellow("this is yellow"))
|
248
|
-
end
|
249
|
-
|
250
|
-
it "returns a partial substring with the appropriate ANSI start sequence and provides an end sequence" do
|
251
|
-
expect(ansi_string[0..1]).to eq blue("th")
|
252
|
-
expect(ansi_string[17..-5]).to eq yellow("is is ye")
|
253
|
-
end
|
254
|
-
|
255
|
-
it "returns the correct substring when location of an ANSI sequence comes before the end of the request" do
|
256
|
-
s = ANSIString.new("ABC \e[7mGemfile.lock\e[0m LICENSE.txt README.md")
|
257
|
-
expect(s[4...28]).to eq ANSIString.new("\e[7mGemfile.lock\e[0m LICENSE.txt")
|
258
|
-
end
|
259
|
-
|
260
|
-
it "returns text that is not ANSI escaped" do
|
261
|
-
expect(ansi_string[12..14]).to eq "ABC"
|
262
|
-
end
|
263
|
-
|
264
|
-
it "returns dos thine" do
|
265
|
-
ansi_string = ANSIString.new("ABC")
|
266
|
-
expect(ansi_string[0...1]).to eq "A"
|
267
|
-
end
|
268
|
-
|
269
|
-
it "returns up to the end" do
|
270
|
-
expect(ansi_string[-2..-1]).to eq yellow("ow")
|
271
|
-
end
|
272
|
-
|
273
|
-
context "and the range is around the ANSI sequence location in the string" do
|
274
|
-
it "returns the string with the ANSI sequences within it intact" do
|
275
|
-
ansi_string = ANSIString.new "abc#{green('def')}ghi"
|
276
|
-
expect(ansi_string[0..-1]).to eq "abc#{green('def')}ghi"
|
277
|
-
end
|
278
|
-
|
279
|
-
it "returns the string with the ANSI sequences within it intact" do
|
280
|
-
ansi_string = ANSIString.new "abc#{green('def')}ghi"
|
281
|
-
expect(ansi_string[0..2]).to eq "abc"
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
it "returns nil when the given range is beyond the length of the string" do
|
286
|
-
ansi_string = ANSIString.new "abc"
|
287
|
-
expect(ansi_string[4]).to be nil
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
describe "#[]=" do
|
292
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
293
|
-
let(:string){ "this is blue" }
|
294
|
-
|
295
|
-
it "returns a new ANSIString with the string at the given index replaced with the new string" do
|
296
|
-
ansi_string[1] = "Z"
|
297
|
-
expect(ansi_string).to eq ANSIString.new(blue("tZis is blue"))
|
298
|
-
end
|
299
|
-
|
300
|
-
it "returns a new ANSIString with the string at the given range replaced with the new string" do
|
301
|
-
ansi_string[1..2] = "ZYX"
|
302
|
-
expect(ansi_string).to eq ANSIString.new(blue("tZYXs is blue"))
|
303
|
-
end
|
304
|
-
|
305
|
-
it "supports replacing with negative indexes at the front of the string" do
|
306
|
-
ansi_string[0..-1] = "abc"
|
307
|
-
expect(ansi_string).to eq ANSIString.new(blue("abc"))
|
308
|
-
end
|
309
|
-
|
310
|
-
it "supports replacing with negative indexes in the middle of the string" do
|
311
|
-
ansi_string = ANSIString.new(blue("abc"))
|
312
|
-
ansi_string[1..-2] = red("*")
|
313
|
-
|
314
|
-
# Do not preserve reset sequences (e.g. "\e[0m") when inserting/replacing.
|
315
|
-
# So no \e[0m before the replacement '*'
|
316
|
-
expect(ansi_string).to eq ANSIString.new("\e[34ma\e[31m*\e[0mc\e[0m")
|
317
|
-
end
|
318
|
-
|
319
|
-
it "preserves coloring when part of the text with a String" do
|
320
|
-
ansi_string[0..3] = "that"
|
321
|
-
expect(ansi_string).to eq ANSIString.new(blue("that is blue"))
|
322
|
-
end
|
323
|
-
|
324
|
-
it "preserves coloring when replacing all of the text with a String" do
|
325
|
-
ansi_string[0..11] = "foobar"
|
326
|
-
expect(ansi_string).to eq ANSIString.new(blue("foobar"))
|
327
|
-
end
|
328
|
-
|
329
|
-
it "preserves coloring when part of the text with a String and we're not starting at an index of 0" do
|
330
|
-
ansi_string[5..6] = "ain't"
|
331
|
-
expect(ansi_string).to eq ANSIString.new(blue("this ain't blue"))
|
332
|
-
end
|
333
|
-
|
334
|
-
context "appending a string to the very end" do
|
335
|
-
subject(:ansi_string){ ANSIString.new green("CircleCI pass") }
|
336
|
-
|
337
|
-
it "combines when the ANSI sequences are the same" do
|
338
|
-
ansi_string[13..15] = ANSIString.new green("ed")
|
339
|
-
expect(ansi_string).to eq ANSIString.new(green("CircleCI passed"))
|
340
|
-
end
|
341
|
-
|
342
|
-
it "doesn't combine when the ANSI sequences are different" do
|
343
|
-
ansi_string[13..15] = ANSIString.new red("ed")
|
344
|
-
expect(ansi_string).to eq ANSIString.new(green("CircleCI pass") + red("ed"))
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
context "replacing on newline boundaries" do
|
349
|
-
subject(:ansi_string){ ANSIString.new "this\nthat" }
|
350
|
-
|
351
|
-
it "keeps the new line intact" do
|
352
|
-
ansi_string[2...4] = "IS"
|
353
|
-
expect(ansi_string).to eq ANSIString.new("thIS\nthat")
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
context "replacing the same location twice" do
|
358
|
-
subject(:ansi_string){ ANSIString.new "this\nthat" }
|
359
|
-
|
360
|
-
it "keeps the new line intact" do
|
361
|
-
ansi_string[2...4] = blue("IS")
|
362
|
-
ansi_string[2...4] = blue("IS")
|
363
|
-
expect(ansi_string).to eq ANSIString.new("th#{blue('IS')}\nthat")
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
context "replacing a substring that goes across ANSI sequence boundaries" do
|
368
|
-
subject(:ansi_string){ ANSIString.new "this#{blue('that')}" }
|
369
|
-
|
370
|
-
it "moves the boundaries when using positive indexes and a regular String replacement" do
|
371
|
-
ansi_string[3..4] = yellow("SORRY")
|
372
|
-
expect(ansi_string).to eq ANSIString.new("thi#{yellow('SORRY')}#{blue('hat')}")
|
373
|
-
end
|
374
|
-
|
375
|
-
it "moves the boundaries when using positive indexes and an ANSIString replacement" do
|
376
|
-
ansi_string[3..4] = yellow("SORRY")
|
377
|
-
expect(ansi_string).to eq ANSIString.new("thi#{yellow('SORRY')}#{blue('hat')}")
|
378
|
-
end
|
379
|
-
|
380
|
-
it "moves the boundaries when using negatives indexes and a regular String replacement" do
|
381
|
-
ansi_string[-5..4] = "SORRY"
|
382
|
-
expect(ansi_string).to eq ANSIString.new("thiSORRY#{blue('hat')}")
|
383
|
-
end
|
384
|
-
|
385
|
-
it "moves the boundaries when using negatives indexes and an ANSIString replacement" do
|
386
|
-
ansi_string[-5..4] = yellow("SORRY")
|
387
|
-
expect(ansi_string).to eq ANSIString.new("thi#{yellow('SORRY')}#{blue('hat')}")
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
context "clearing the string" do
|
392
|
-
subject(:ansi_string){ ANSIString.new "this\nthat" }
|
393
|
-
|
394
|
-
it "clears the string" do
|
395
|
-
ansi_string[0..-1] = ""
|
396
|
-
expect(ansi_string).to eq ANSIString.new("")
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
context "expanding a string" do
|
401
|
-
subject(:ansi_string){ ANSIString.new "" }
|
402
|
-
|
403
|
-
it "expands the string" do
|
404
|
-
ansi_string[0..-1] = ANSIString.new(blue("HI"))
|
405
|
-
expect(ansi_string).to eq ANSIString.new(blue("HI"))
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
it "raises an error out of index" do
|
410
|
-
expect {
|
411
|
-
ansi_string[14..15] = string
|
412
|
-
}.to raise_error(RangeError, "14..15 out of range")
|
413
|
-
end
|
414
|
-
|
415
|
-
context "replacing a substring that comes entirely after an ANSI sequence" do
|
416
|
-
subject(:ansi_string){ ANSIString.new "this #{blue('is')} your television screen." }
|
417
|
-
|
418
|
-
it "places the substring in the correct location" do
|
419
|
-
ansi_string[14..15] = "YO YO"
|
420
|
-
expect(ansi_string).to eq ANSIString.new "this #{blue('is')} your tYO YOevision screen."
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
describe "#dup" do
|
426
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
427
|
-
let(:string){ "this is blue" }
|
428
|
-
|
429
|
-
it "returns a dup'd version of itself" do
|
430
|
-
duped = ansi_string.dup
|
431
|
-
expect(duped).to be_kind_of(ANSIString)
|
432
|
-
expect(duped.raw).to eq(ansi_string.raw)
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
describe "#lines" do
|
437
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
438
|
-
let(:string){ "this\nis\nblue" }
|
439
|
-
|
440
|
-
it "returns lines" do
|
441
|
-
expect(ansi_string.lines).to eq [
|
442
|
-
ANSIString.new(blue("this\n")),
|
443
|
-
ANSIString.new(blue("is\n")),
|
444
|
-
ANSIString.new(blue("blue"))
|
445
|
-
]
|
446
|
-
end
|
447
|
-
|
448
|
-
it "returns lines" do
|
449
|
-
ansi_string = ANSIString.new blue("abc") + "\n" + red("d\nef") + "hi\n" + yellow("foo")
|
450
|
-
expect(ansi_string.lines).to eq [
|
451
|
-
ANSIString.new(blue("abc") + "\n"),
|
452
|
-
ANSIString.new(red("d\n")),
|
453
|
-
ANSIString.new(red("ef") + "hi\n"),
|
454
|
-
ANSIString.new(yellow("foo"))
|
455
|
-
]
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
describe "#==" do
|
460
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
461
|
-
let(:string){ "this is blue" }
|
462
|
-
|
463
|
-
it "returns true when comparing against itself" do
|
464
|
-
expect(ansi_string).to eq ansi_string
|
465
|
-
end
|
466
|
-
|
467
|
-
it "returns true when comparing against another ANSIString with the same contents" do
|
468
|
-
expect(ansi_string).to eq ANSIString.new(blue(string))
|
469
|
-
end
|
470
|
-
|
471
|
-
it "returns false when comparing against another ANSIString with differnent contents" do
|
472
|
-
expect(ansi_string).to_not eq ANSIString.new(blue("other stuff"))
|
473
|
-
end
|
474
|
-
|
475
|
-
it "returns true when comparing against a String with the same raw contents" do
|
476
|
-
expect(ansi_string).to eq blue(string)
|
477
|
-
end
|
478
|
-
|
479
|
-
it "returns true when comparing against a String that doesn't match its raw contents" do
|
480
|
-
expect(ansi_string).to_not eq "asfsd"
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
describe "<=>" do
|
485
|
-
let(:string_1){ ANSIString.new blue("abc") }
|
486
|
-
let(:string_2){ ANSIString.new blue("def") }
|
487
|
-
|
488
|
-
it "behaves the same as a normal string" do
|
489
|
-
expect(string_1 <=> string_2).to eq(-1)
|
490
|
-
expect(string_1 <=> string_1).to eq(0)
|
491
|
-
expect(string_2 <=> string_1).to eq(1)
|
492
|
-
end
|
493
|
-
end
|
494
|
-
|
495
|
-
describe "#match" do
|
496
|
-
it "matches on a string pattren" do
|
497
|
-
string = "apples are bananas are they not?"
|
498
|
-
ansi_string = ANSIString.new("app#{red('les are bananas')} are they not?")
|
499
|
-
expect(ansi_string.match("are")).to eq(string.match("are"))
|
500
|
-
end
|
501
|
-
|
502
|
-
it "matches on a regex pattren" do
|
503
|
-
string = "apples are bananas are they not?"
|
504
|
-
ansi_string = ANSIString.new("app#{red('les are bananas')} are they not?")
|
505
|
-
expect(ansi_string.match(/are/)).to eq(string.match(/are/))
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
describe "#=~" do
|
510
|
-
it "matches on a regex pattren" do
|
511
|
-
string = "apples are bananas are they not?"
|
512
|
-
ansi_string = ANSIString.new("app#{red('les are bananas')} are they not?")
|
513
|
-
expect(ansi_string =~ /are/).to eq(string =~ /are/)
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
describe "#scan" do
|
518
|
-
it "scans without capture groups" do
|
519
|
-
string = "567"
|
520
|
-
ansi_string = ANSIString.new("1234#{red('5678')}90")
|
521
|
-
expect(ansi_string.scan(/.{2}/)).to eq([
|
522
|
-
ANSIString.new("12"),
|
523
|
-
ANSIString.new("34"),
|
524
|
-
ANSIString.new("#{red('56')}"),
|
525
|
-
ANSIString.new("#{red('78')}"),
|
526
|
-
ANSIString.new("90")
|
527
|
-
])
|
528
|
-
end
|
529
|
-
|
530
|
-
it "scans with capture groups" do
|
531
|
-
string = "567"
|
532
|
-
ansi_string = ANSIString.new("1234#{red('5678')}90")
|
533
|
-
expect(ansi_string.scan(/(.)./)).to eq([
|
534
|
-
[ANSIString.new("1")],
|
535
|
-
[ANSIString.new("3")],
|
536
|
-
[ANSIString.new("#{red('5')}")],
|
537
|
-
[ANSIString.new("#{red('7')}")],
|
538
|
-
[ANSIString.new("9")]
|
539
|
-
])
|
540
|
-
end
|
541
|
-
end
|
542
|
-
|
543
|
-
describe "#replace" do
|
544
|
-
it "replaces the contents of the current string with the new string" do
|
545
|
-
ansi_string = ANSIString.new("abc")
|
546
|
-
original_object_id = ansi_string.object_id
|
547
|
-
expect(ansi_string.replace("def")).to eq ANSIString.new("def")
|
548
|
-
expect(ansi_string.object_id).to eq(original_object_id)
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
describe "#reverse" do
|
553
|
-
it "reverses the string" do
|
554
|
-
ansi_string = ANSIString.new("abc")
|
555
|
-
expect(ansi_string.reverse).to eq ANSIString.new("cba")
|
556
|
-
end
|
557
|
-
|
558
|
-
it "reverses the string with ANSI sequences" do
|
559
|
-
ansi_string = ANSIString.new("a#{blue('b')}#{yellow('c')}")
|
560
|
-
expect(ansi_string.reverse).to eq ANSIString.new("#{yellow('c')}#{blue('b')}a")
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
describe "#slice" do
|
565
|
-
it "returns a substring of one character given a numeric index" do
|
566
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
567
|
-
expect(ansi_string.slice(0)).to eq ANSIString.new("a")
|
568
|
-
expect(ansi_string.slice(1)).to eq ANSIString.new(blue("b"))
|
569
|
-
expect(ansi_string.slice(2)).to eq ANSIString.new("c")
|
570
|
-
end
|
571
|
-
|
572
|
-
it "returns a substring of characters of N length given a start index and max length N" do
|
573
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
574
|
-
expect(ansi_string.slice(0, 0)).to eq ANSIString.new("")
|
575
|
-
expect(ansi_string.slice(0, 2)).to eq ANSIString.new("a#{blue('b')}")
|
576
|
-
expect(ansi_string.slice(1, 2)).to eq ANSIString.new("#{blue('b')}c")
|
577
|
-
|
578
|
-
# length is over, doesn't blow up
|
579
|
-
expect(ansi_string.slice(1, 3)).to eq ANSIString.new("#{blue('b')}c")
|
580
|
-
end
|
581
|
-
|
582
|
-
it "returns a substring of characters using a range as delimiters" do
|
583
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
584
|
-
expect(ansi_string.slice(0..1)).to eq ANSIString.new("a#{blue('b')}")
|
585
|
-
expect(ansi_string.slice(0...2)).to eq ANSIString.new("a#{blue('b')}")
|
586
|
-
|
587
|
-
# length is over, doesn't blow up
|
588
|
-
expect(ansi_string.slice(1..3)).to eq ANSIString.new("#{blue('b')}c")
|
589
|
-
end
|
590
|
-
|
591
|
-
it "returns a substring of characters matching the given regex" do
|
592
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
593
|
-
expect(ansi_string.slice(/b/)).to eq ANSIString.new("#{blue('b')}")
|
594
|
-
expect(ansi_string.slice(/(b)c/)).to eq ANSIString.new("#{blue('b')}c")
|
595
|
-
|
596
|
-
# length is over, doesn't blow up
|
597
|
-
expect(ansi_string.slice(/.*/)).to eq ANSIString.new("a#{blue('b')}c")
|
598
|
-
end
|
599
|
-
|
600
|
-
it "returns a substring for the capture group matching the given regex and capture group index" do
|
601
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
602
|
-
expect(ansi_string.slice(/((a)(b)(c))/, 1)).to eq ANSIString.new("a#{blue('b')}c")
|
603
|
-
expect(ansi_string.slice(/((a)(b)(c))/, 2)).to eq ANSIString.new("a")
|
604
|
-
expect(ansi_string.slice(/((a)(b)(c))/, 3)).to eq ANSIString.new("#{blue('b')}")
|
605
|
-
expect(ansi_string.slice(/((a)(b)(c))/, 4)).to eq ANSIString.new("c")
|
606
|
-
end
|
607
|
-
|
608
|
-
it "returns the substring when a given string is found" do
|
609
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
610
|
-
expect(ansi_string.slice("bc")).to eq(ANSIString.new("#{blue('b')}c"))
|
611
|
-
end
|
612
|
-
|
613
|
-
it "returns nil when no matches are found" do
|
614
|
-
ansi_string = ANSIString.new("a#{blue('b')}c")
|
615
|
-
expect(ansi_string.slice("zzz")).to be nil
|
616
|
-
expect(ansi_string.slice(/zzz/)).to be nil
|
617
|
-
expect(ansi_string.slice(99)).to be nil
|
618
|
-
expect(ansi_string.slice(99, 100)).to be nil
|
619
|
-
expect(ansi_string.slice(99..100)).to be nil
|
620
|
-
end
|
621
|
-
end
|
622
|
-
|
623
|
-
describe "#split" do
|
624
|
-
it "splits on the given string pattern" do
|
625
|
-
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
626
|
-
expect(ansi_string.split(". ")).to eq([
|
627
|
-
ANSIString.new("apples are #{red('red')}"),
|
628
|
-
ANSIString.new("bananas are #{blue('blue')}"),
|
629
|
-
ANSIString.new("cats are #{yellow('yellow')}.")
|
630
|
-
])
|
631
|
-
end
|
632
|
-
|
633
|
-
it "splits on the given regex pattern" do
|
634
|
-
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
635
|
-
expect(ansi_string.split(/\.\s?/)).to eq([
|
636
|
-
ANSIString.new("apples are #{red('red')}"),
|
637
|
-
ANSIString.new("bananas are #{blue('blue')}"),
|
638
|
-
ANSIString.new("cats are #{yellow('yellow')}")
|
639
|
-
])
|
640
|
-
end
|
641
|
-
|
642
|
-
it "limits how many times it splits with a secondary limit argument" do
|
643
|
-
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
644
|
-
expect(ansi_string.split(/\.\s?/, 2)).to eq([
|
645
|
-
ANSIString.new("apples are #{red('red')}"),
|
646
|
-
ANSIString.new("bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
647
|
-
])
|
648
|
-
end
|
649
|
-
end
|
650
|
-
|
651
|
-
describe "#strip" do
|
652
|
-
it 'returns a copy of the string with leading and trailing whitespace removed' do
|
653
|
-
ansi_string = ANSIString.new " this is his #{blue('pig')} "
|
654
|
-
expect(ansi_string.strip).to eq ANSIString.new "this is his #{blue('pig')}"
|
655
|
-
expect(ansi_string).to eq ANSIString.new " this is his #{blue('pig')} "
|
656
|
-
end
|
657
|
-
end
|
658
|
-
|
659
|
-
describe "#sub" do
|
660
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
661
|
-
let(:string){ "this is blue" }
|
662
|
-
|
663
|
-
it "returns an ANSIString" do
|
664
|
-
expect(ansi_string.sub(/ is /, "")).to eq ANSIString.new(blue("thisblue"))
|
665
|
-
end
|
666
|
-
|
667
|
-
it "works across ansi sequences" do
|
668
|
-
blue_string = blue("this is blue")
|
669
|
-
yellow_string = yellow("this is yellow")
|
670
|
-
non_colored_string = "hi there\nbye there"
|
671
|
-
str = ANSIString.new(blue_string + yellow_string + non_colored_string + " \n \n \n ")
|
672
|
-
expect(str.sub(/\s*\Z/m, "")).to eq ANSIString.new(blue_string + yellow_string + non_colored_string)
|
673
|
-
end
|
674
|
-
end
|
675
|
-
|
676
|
-
describe "#gsub" do
|
677
|
-
it "needs to be implemented"
|
678
|
-
end
|
679
|
-
|
680
|
-
describe "#to_s" do
|
681
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
682
|
-
let(:string){ "this is blue" }
|
683
|
-
|
684
|
-
it "returns the ANSI capable string" do
|
685
|
-
expect(ansi_string.to_s).to eq blue(string)
|
686
|
-
end
|
687
|
-
end
|
688
|
-
|
689
|
-
describe "#inspect" do
|
690
|
-
subject(:ansi_string){ ANSIString.new blue(string) }
|
691
|
-
let(:string){ "this is blue" }
|
692
|
-
|
693
|
-
it "returns a quoted version of the strong" do
|
694
|
-
expect(ansi_string.inspect).to eq "\"\\e[34mthis is blue\\e[0m\""
|
695
|
-
end
|
696
|
-
end
|
697
|
-
|
698
|
-
describe "#succ" do
|
699
|
-
it "needs to be implemented"
|
700
|
-
end
|
701
|
-
end
|