terminal-layout 0.1.0
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 +7 -0
- data/.rspec +2 -0
- data/.travis.yml +14 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +60 -0
- data/README.md +7 -0
- data/block-flow.rb +361 -0
- data/lib/ansi_string.rb +315 -0
- data/lib/terminal_layout.rb +527 -0
- data/spec/ansi_string_spec.rb +499 -0
- data/spec/spec_helper.rb +102 -0
- data/spec/terminal_layout_spec.rb +745 -0
- data/terminal-layout.gemspec +28 -0
- data/test-1.rb +90 -0
- metadata +158 -0
@@ -0,0 +1,499 @@
|
|
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
|
+
end
|
18
|
+
|
19
|
+
describe "redundant ANSI sequences" do
|
20
|
+
it "strips out redundant ANSI sequences that are immediately next to each other" do
|
21
|
+
ansi_string = ANSIString.new "this is\e[31m\e[31m a string"
|
22
|
+
expect(ansi_string.to_s).to eq "this is\e[31m a string"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "strips out redundant ANSI sequences that are not immediately next to each other" do
|
26
|
+
ansi_string = ANSIString.new "this \e[31m a\e[31m string"
|
27
|
+
expect(ansi_string.to_s).to eq "this \e[31m a string"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "does not strip out ANSI sequences that differ" do
|
31
|
+
ansi_string = ANSIString.new "this \e[31m a\e[32m string"
|
32
|
+
expect(ansi_string.to_s).to eq "this \e[31m a\e[32m string"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#+ combining strings" do
|
37
|
+
let(:blue_ansi_string){ ANSIString.new blue_string }
|
38
|
+
let(:yellow_ansi_string){ ANSIString.new yellow_string }
|
39
|
+
let(:blue_string){ blue("this is blue") }
|
40
|
+
let(:yellow_string){ yellow("this is yellow") }
|
41
|
+
|
42
|
+
it "returns a new string when combining two ANSIStrings" do
|
43
|
+
expect(blue_ansi_string + yellow_ansi_string).to eq ANSIString.new(blue_string + yellow_string)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns a new string when combining a ANIString with a String" do
|
47
|
+
expect(blue_ansi_string + yellow_string).to eq ANSIString.new(blue_string + yellow_string)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#<<" do
|
52
|
+
it "appends a String onto the end of the current ANSIString" do
|
53
|
+
ansi_string = ANSIString.new ""
|
54
|
+
ansi_string << "a"
|
55
|
+
expect(ansi_string).to eq ANSIString.new("a")
|
56
|
+
|
57
|
+
ansi_string << "b"
|
58
|
+
expect(ansi_string).to eq ANSIString.new("ab")
|
59
|
+
|
60
|
+
ansi_string << "cd"
|
61
|
+
expect(ansi_string).to eq ANSIString.new("abcd")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "appends an ANSIString onto the end of the current ANSIString" do
|
65
|
+
ansi_string = ANSIString.new ""
|
66
|
+
ansi_string << ANSIString.new(blue("a"))
|
67
|
+
expect(ansi_string).to eq ANSIString.new("#{blue('a')}")
|
68
|
+
|
69
|
+
ansi_string << ANSIString.new(yellow("b"))
|
70
|
+
expect(ansi_string).to eq ANSIString.new("#{blue('a')}#{yellow('b')}")
|
71
|
+
|
72
|
+
ansi_string << ANSIString.new(red("cd"))
|
73
|
+
expect(ansi_string).to eq ANSIString.new("#{blue('a')}#{yellow('b')}#{red('cd')}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#length" do
|
78
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
79
|
+
let(:string){ "this is blue" }
|
80
|
+
|
81
|
+
it "returns the length string without ANSI escape sequences" do
|
82
|
+
expect(ansi_string.length).to eq string.length
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#index" do
|
87
|
+
it "returns the index of the first occurrence of the given substring" do
|
88
|
+
ansi_string = ANSIString.new("this is not blue")
|
89
|
+
expect(ansi_string.index("b")).to eq 12
|
90
|
+
|
91
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
92
|
+
expect(ansi_string.index("blu")).to eq 8
|
93
|
+
|
94
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
95
|
+
expect(ansi_string.index("yellow")).to eq 25
|
96
|
+
end
|
97
|
+
|
98
|
+
it "returns the index starting on or after an optional start position" do
|
99
|
+
ansi_string = ANSIString.new("this is not blue")
|
100
|
+
expect(ansi_string.index("t", 0)).to eq 0
|
101
|
+
|
102
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
103
|
+
expect(ansi_string.index("is", 3)).to eq 5
|
104
|
+
expect(ansi_string.index("bl", 7)).to eq 8
|
105
|
+
expect(ansi_string.index("bl", 9)).to eq nil
|
106
|
+
|
107
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
108
|
+
expect(ansi_string.index("yel", 5)).to eq 25
|
109
|
+
expect(ansi_string.index("yel", 25)).to eq 25
|
110
|
+
expect(ansi_string.index("yel", 26)).to eq nil
|
111
|
+
end
|
112
|
+
|
113
|
+
it "returns the index of the first occurrence of the given regular expression" do
|
114
|
+
ansi_string = ANSIString.new("this is not blue")
|
115
|
+
expect(ansi_string.index(/b/)).to eq 12
|
116
|
+
|
117
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
118
|
+
expect(ansi_string.index(/blu/)).to eq 8
|
119
|
+
|
120
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
121
|
+
expect(ansi_string.index(/y.ll.w/)).to eq 25
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#rindex" do
|
126
|
+
it "returns the index of the last occurrence of the given substring" do
|
127
|
+
ansi_string = ANSIString.new("this is not blue")
|
128
|
+
expect(ansi_string.rindex("i")).to eq 5
|
129
|
+
|
130
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
131
|
+
expect(ansi_string.rindex("blu")).to eq 8
|
132
|
+
|
133
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
134
|
+
expect(ansi_string.rindex("yellow")).to eq 25
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns the index of the match on or after an optional stop position" do
|
138
|
+
ansi_string = ANSIString.new("this is not blue")
|
139
|
+
expect(ansi_string.rindex("t", 0)).to eq 0
|
140
|
+
expect(ansi_string.rindex("is", 3)).to eq 2
|
141
|
+
expect(ansi_string.rindex("bl", 12)).to eq 12
|
142
|
+
|
143
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
144
|
+
expect(ansi_string.rindex("is", 0)).to eq nil
|
145
|
+
expect(ansi_string.rindex("is", 3)).to eq 2
|
146
|
+
expect(ansi_string.rindex("bl", 8)).to eq 8
|
147
|
+
expect(ansi_string.rindex("bl", 12)).to eq 8
|
148
|
+
|
149
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
150
|
+
expect(ansi_string.rindex("yel", 5)).to eq nil
|
151
|
+
expect(ansi_string.rindex("yel", 25)).to eq 25
|
152
|
+
expect(ansi_string.rindex("yel", 26)).to eq 25
|
153
|
+
end
|
154
|
+
|
155
|
+
it "returns the index of the last occurrence of the given regular expression" do
|
156
|
+
ansi_string = ANSIString.new("this is not blue")
|
157
|
+
expect(ansi_string.rindex(/b/)).to eq 12
|
158
|
+
|
159
|
+
ansi_string = ANSIString.new("this is #{blue('blue')}")
|
160
|
+
expect(ansi_string.rindex(/blu/)).to eq 8
|
161
|
+
|
162
|
+
ansi_string = ANSIString.new("this is #{blue('blue')} and this is #{yellow('yellow')}")
|
163
|
+
expect(ansi_string.rindex(/y.ll.w/)).to eq 25
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "#[]" do
|
168
|
+
subject(:ansi_string){ ANSIString.new "#{blue_string}ABC#{yellow_string}" }
|
169
|
+
let(:blue_string){ blue("this is blue") }
|
170
|
+
let(:yellow_string){ yellow("this is yellow") }
|
171
|
+
|
172
|
+
it "returns the full substring with the appropriate ANSI start and end sequence" do
|
173
|
+
expect(ansi_string[0...12]).to eq ANSIString.new(blue("this is blue"))
|
174
|
+
expect(ansi_string[15..-1]).to eq ANSIString.new(yellow("this is yellow"))
|
175
|
+
end
|
176
|
+
|
177
|
+
it "returns a partial substring with the appropriate ANSI start sequence and provides an end sequence" do
|
178
|
+
expect(ansi_string[0..1]).to eq blue("th")
|
179
|
+
expect(ansi_string[17..-5]).to eq yellow("is is ye")
|
180
|
+
end
|
181
|
+
|
182
|
+
it "returns text that is not ANSI escaped" do
|
183
|
+
expect(ansi_string[12..14]).to eq "ABC"
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns up to the end" do
|
187
|
+
expect(ansi_string[-2..-1]).to eq yellow("ow")
|
188
|
+
end
|
189
|
+
|
190
|
+
context "and the range is around the ANSI sequence location in the string" do
|
191
|
+
it "returns the string with the ANSI sequences within it intact" do
|
192
|
+
ansi_string = ANSIString.new "abc#{green('def')}ghi"
|
193
|
+
expect(ansi_string[0..-1]).to eq "abc#{green('def')}ghi"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "returns the string with the ANSI sequences within it intact" do
|
197
|
+
ansi_string = ANSIString.new "abc#{green('def')}ghi"
|
198
|
+
expect(ansi_string[0..2]).to eq "abc"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
it "returns nil when the given range is beyond the length of the string" do
|
203
|
+
ansi_string = ANSIString.new "abc"
|
204
|
+
expect(ansi_string[4]).to be nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "#[]=" do
|
209
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
210
|
+
let(:string){ "this is blue" }
|
211
|
+
|
212
|
+
it "returns a new ANSIString with the string at the given index replaced with the new string" do
|
213
|
+
ansi_string[1] = "Z"
|
214
|
+
expect(ansi_string).to eq ANSIString.new(blue("tZis is blue"))
|
215
|
+
end
|
216
|
+
|
217
|
+
it "returns a new ANSIString with the string at the given range replaced with the new string" do
|
218
|
+
ansi_string[1..2] = "ZYX"
|
219
|
+
expect(ansi_string).to eq ANSIString.new(blue("tZYXs is blue"))
|
220
|
+
end
|
221
|
+
|
222
|
+
it "preserves coloring when part of the text with a String" do
|
223
|
+
ansi_string[0..3] = "that"
|
224
|
+
expect(ansi_string).to eq ANSIString.new(blue("that is blue"))
|
225
|
+
end
|
226
|
+
|
227
|
+
it "preserves coloring when replacing all of the text with a String" do
|
228
|
+
ansi_string[0..11] = "foobar"
|
229
|
+
expect(ansi_string).to eq ANSIString.new(blue("foobar"))
|
230
|
+
end
|
231
|
+
|
232
|
+
it "preserves coloring when part of the text with a String and we're not starting at an index of 0" do
|
233
|
+
ansi_string[5..6] = "ain't"
|
234
|
+
expect(ansi_string).to eq ANSIString.new(blue("this ain't blue"))
|
235
|
+
end
|
236
|
+
|
237
|
+
context "appending a string to the very end" do
|
238
|
+
subject(:ansi_string){ ANSIString.new green("CircleCI pass") }
|
239
|
+
|
240
|
+
it "combines when the ANSI sequences are the same" do
|
241
|
+
ansi_string[13..15] = ANSIString.new green("ed")
|
242
|
+
expect(ansi_string).to eq ANSIString.new(green("CircleCI passed"))
|
243
|
+
end
|
244
|
+
|
245
|
+
it "doesn't combine when the ANSI sequences are different" do
|
246
|
+
ansi_string[13..15] = ANSIString.new red("ed")
|
247
|
+
expect(ansi_string).to eq ANSIString.new(green("CircleCI pass") + red("ed"))
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context "replacing on newline boundaries" do
|
252
|
+
subject(:ansi_string){ ANSIString.new "this\nthat" }
|
253
|
+
|
254
|
+
it "keeps the new line intact" do
|
255
|
+
ansi_string[2...4] = "IS"
|
256
|
+
expect(ansi_string).to eq ANSIString.new("thIS\nthat")
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context "replacing the same location twice" do
|
261
|
+
subject(:ansi_string){ ANSIString.new "this\nthat" }
|
262
|
+
|
263
|
+
it "keeps the new line intact" do
|
264
|
+
ansi_string[2...4] = blue("IS")
|
265
|
+
ansi_string[2...4] = blue("IS")
|
266
|
+
expect(ansi_string).to eq ANSIString.new("th#{blue('IS')}\nthat")
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "replacing a substring that goes across ANSI sequence boundaries" do
|
271
|
+
subject(:ansi_string){ ANSIString.new "this#{blue('that')}" }
|
272
|
+
|
273
|
+
it "successfully moves the boundaries" do
|
274
|
+
ansi_string[3..4] = yellow("SORRY")
|
275
|
+
expect(ansi_string).to eq ANSIString.new("thi#{yellow('SORRY')}#{blue('hat')}")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
it "raises an error out of index" do
|
280
|
+
expect {
|
281
|
+
ansi_string[14..15] = string
|
282
|
+
}.to raise_error(RangeError, "14..15 out of range")
|
283
|
+
end
|
284
|
+
|
285
|
+
context "replacing a substring that comes entirely after an ANSI sequence" do
|
286
|
+
subject(:ansi_string){ ANSIString.new "this #{blue('is')} your television screen." }
|
287
|
+
|
288
|
+
it "places the substring in the correct location" do
|
289
|
+
ansi_string[14..15] = "YO YO"
|
290
|
+
expect(ansi_string).to eq ANSIString.new "this #{blue('is')} your tYO YOevision screen."
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "#dup" do
|
296
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
297
|
+
let(:string){ "this is blue" }
|
298
|
+
|
299
|
+
it "returns a dup'd version of itself" do
|
300
|
+
duped = ansi_string.dup
|
301
|
+
expect(duped).to be_kind_of(ANSIString)
|
302
|
+
expect(duped.raw).to eq(ansi_string.raw)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "#lines" do
|
307
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
308
|
+
let(:string){ "this\nis\nblue" }
|
309
|
+
|
310
|
+
it "returns lines" do
|
311
|
+
expect(ansi_string.lines).to eq [
|
312
|
+
ANSIString.new(blue("this\n")),
|
313
|
+
ANSIString.new(blue("is\n")),
|
314
|
+
ANSIString.new(blue("blue"))
|
315
|
+
]
|
316
|
+
end
|
317
|
+
|
318
|
+
it "returns lines" do
|
319
|
+
ansi_string = ANSIString.new blue("abc") + "\n" + red("d\nef") + "hi\n" + yellow("foo")
|
320
|
+
expect(ansi_string.lines).to eq [
|
321
|
+
ANSIString.new(blue("abc") + "\n"),
|
322
|
+
ANSIString.new(red("d\n")),
|
323
|
+
ANSIString.new(red("ef") + "hi\n"),
|
324
|
+
ANSIString.new(yellow("foo"))
|
325
|
+
]
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
describe "#==" do
|
330
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
331
|
+
let(:string){ "this is blue" }
|
332
|
+
|
333
|
+
it "returns true when comparing against itself" do
|
334
|
+
expect(ansi_string).to eq ansi_string
|
335
|
+
end
|
336
|
+
|
337
|
+
it "returns true when comparing against another ANSIString with the same contents" do
|
338
|
+
expect(ansi_string).to eq ANSIString.new(blue(string))
|
339
|
+
end
|
340
|
+
|
341
|
+
it "returns false when comparing against another ANSIString with differnent contents" do
|
342
|
+
expect(ansi_string).to_not eq ANSIString.new(blue("other stuff"))
|
343
|
+
end
|
344
|
+
|
345
|
+
it "returns true when comparing against a String with the same raw contents" do
|
346
|
+
expect(ansi_string).to eq blue(string)
|
347
|
+
end
|
348
|
+
|
349
|
+
it "returns true when comparing against a String that doesn't match its raw contents" do
|
350
|
+
expect(ansi_string).to_not eq "asfsd"
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "#match" do
|
355
|
+
it "matches on a string pattren" do
|
356
|
+
string = "apples are bananas are they not?"
|
357
|
+
ansi_string = ANSIString.new("app#{red('les are bananas')} are they not?")
|
358
|
+
expect(ansi_string.match("are")).to eq(string.match("are"))
|
359
|
+
end
|
360
|
+
|
361
|
+
it "matches on a regex pattren" do
|
362
|
+
string = "apples are bananas are they not?"
|
363
|
+
ansi_string = ANSIString.new("app#{red('les are bananas')} are they not?")
|
364
|
+
expect(ansi_string.match(/are/)).to eq(string.match(/are/))
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe "#reverse" do
|
369
|
+
it "reverses the string" do
|
370
|
+
ansi_string = ANSIString.new("abc")
|
371
|
+
expect(ansi_string.reverse).to eq ANSIString.new("cba")
|
372
|
+
end
|
373
|
+
|
374
|
+
it "reverses the string with ANSI sequences" do
|
375
|
+
ansi_string = ANSIString.new("a#{blue('b')}#{yellow('c')}")
|
376
|
+
expect(ansi_string.reverse).to eq ANSIString.new("#{yellow('c')}#{blue('b')}a")
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
describe "#slice" do
|
381
|
+
it "returns a substring of one character given a numeric index" do
|
382
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
383
|
+
expect(ansi_string.slice(0)).to eq ANSIString.new("a")
|
384
|
+
expect(ansi_string.slice(1)).to eq ANSIString.new(blue("b"))
|
385
|
+
expect(ansi_string.slice(2)).to eq ANSIString.new("c")
|
386
|
+
end
|
387
|
+
|
388
|
+
it "returns a substring of characters of N length given a start index and max length N" do
|
389
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
390
|
+
expect(ansi_string.slice(0, 2)).to eq ANSIString.new("a#{blue('b')}")
|
391
|
+
expect(ansi_string.slice(1, 2)).to eq ANSIString.new("#{blue('b')}c")
|
392
|
+
|
393
|
+
# length is over, doesn't blow up
|
394
|
+
expect(ansi_string.slice(1, 3)).to eq ANSIString.new("#{blue('b')}c")
|
395
|
+
end
|
396
|
+
|
397
|
+
it "returns a substring of characters using a range as delimiters" do
|
398
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
399
|
+
expect(ansi_string.slice(0..1)).to eq ANSIString.new("a#{blue('b')}")
|
400
|
+
expect(ansi_string.slice(0...2)).to eq ANSIString.new("a#{blue('b')}")
|
401
|
+
|
402
|
+
# length is over, doesn't blow up
|
403
|
+
expect(ansi_string.slice(1..3)).to eq ANSIString.new("#{blue('b')}c")
|
404
|
+
end
|
405
|
+
|
406
|
+
it "returns a substring of characters matching the given regex" do
|
407
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
408
|
+
expect(ansi_string.slice(/b/)).to eq ANSIString.new("#{blue('b')}")
|
409
|
+
expect(ansi_string.slice(/(b)c/)).to eq ANSIString.new("#{blue('b')}c")
|
410
|
+
|
411
|
+
# length is over, doesn't blow up
|
412
|
+
expect(ansi_string.slice(/.*/)).to eq ANSIString.new("a#{blue('b')}c")
|
413
|
+
end
|
414
|
+
|
415
|
+
it "returns a substring for the capture group matching the given regex and capture group index" do
|
416
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
417
|
+
expect(ansi_string.slice(/((a)(b)(c))/, 1)).to eq ANSIString.new("a#{blue('b')}c")
|
418
|
+
expect(ansi_string.slice(/((a)(b)(c))/, 2)).to eq ANSIString.new("a")
|
419
|
+
expect(ansi_string.slice(/((a)(b)(c))/, 3)).to eq ANSIString.new("#{blue('b')}")
|
420
|
+
expect(ansi_string.slice(/((a)(b)(c))/, 4)).to eq ANSIString.new("c")
|
421
|
+
end
|
422
|
+
|
423
|
+
it "returns the substring when a given string is found" do
|
424
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
425
|
+
expect(ansi_string.slice("bc")).to eq(ANSIString.new("#{blue('b')}c"))
|
426
|
+
end
|
427
|
+
|
428
|
+
it "returns nil when no matches are found" do
|
429
|
+
ansi_string = ANSIString.new("a#{blue('b')}c")
|
430
|
+
expect(ansi_string.slice("zzz")).to be nil
|
431
|
+
expect(ansi_string.slice(/zzz/)).to be nil
|
432
|
+
expect(ansi_string.slice(99)).to be nil
|
433
|
+
expect(ansi_string.slice(99, 100)).to be nil
|
434
|
+
expect(ansi_string.slice(99..100)).to be nil
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
describe "#split" do
|
439
|
+
it "splits on the given string pattern" do
|
440
|
+
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
441
|
+
expect(ansi_string.split(". ")).to eq([
|
442
|
+
ANSIString.new("apples are #{red('red')}"),
|
443
|
+
ANSIString.new("bananas are #{blue('blue')}"),
|
444
|
+
ANSIString.new("cats are #{yellow('yellow')}.")
|
445
|
+
])
|
446
|
+
end
|
447
|
+
|
448
|
+
it "splits on the given regex pattern" do
|
449
|
+
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
450
|
+
expect(ansi_string.split(/\.\s?/)).to eq([
|
451
|
+
ANSIString.new("apples are #{red('red')}"),
|
452
|
+
ANSIString.new("bananas are #{blue('blue')}"),
|
453
|
+
ANSIString.new("cats are #{yellow('yellow')}")
|
454
|
+
])
|
455
|
+
end
|
456
|
+
|
457
|
+
it "limits how many times it splits with a secondary limit argument" do
|
458
|
+
ansi_string = ANSIString.new("apples are #{red('red')}. bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
459
|
+
expect(ansi_string.split(/\.\s?/, 2)).to eq([
|
460
|
+
ANSIString.new("apples are #{red('red')}"),
|
461
|
+
ANSIString.new("bananas are #{blue('blue')}. cats are #{yellow('yellow')}.")
|
462
|
+
])
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
describe "#sub" do
|
467
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
468
|
+
let(:string){ "this is blue" }
|
469
|
+
|
470
|
+
it "returns an ANSIString" do
|
471
|
+
expect(ansi_string.sub(/ is /, "")).to eq ANSIString.new(blue("thisblue"))
|
472
|
+
end
|
473
|
+
|
474
|
+
it "works across ansi sequences" do
|
475
|
+
blue_string = blue("this is blue")
|
476
|
+
yellow_string = yellow("this is yellow")
|
477
|
+
non_colored_string = "hi there\nbye there"
|
478
|
+
str = ANSIString.new(blue_string + yellow_string + non_colored_string + " \n \n \n ")
|
479
|
+
expect(str.sub(/\s*\Z/m, "")).to eq ANSIString.new(blue_string + yellow_string + non_colored_string)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
describe "#gsub" do
|
484
|
+
it "needs to be implemented"
|
485
|
+
end
|
486
|
+
|
487
|
+
describe "#to_s" do
|
488
|
+
subject(:ansi_string){ ANSIString.new blue(string) }
|
489
|
+
let(:string){ "this is blue" }
|
490
|
+
|
491
|
+
it "returns the ANSI capable string" do
|
492
|
+
expect(ansi_string.to_s).to eq blue(string)
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
describe "#succ" do
|
497
|
+
it "needs to be implemented"
|
498
|
+
end
|
499
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
2
|
+
|
3
|
+
require 'pry'
|
4
|
+
require 'terminal_layout'
|
5
|
+
require 'ansi_string'
|
6
|
+
|
7
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
8
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
9
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
10
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
11
|
+
# files.
|
12
|
+
#
|
13
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
14
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
15
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
16
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
17
|
+
# a separate helper file that requires the additional dependencies and performs
|
18
|
+
# the additional setup, and require it from the spec files that actually need
|
19
|
+
# it.
|
20
|
+
#
|
21
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
22
|
+
# users commonly want.
|
23
|
+
#
|
24
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
25
|
+
RSpec.configure do |config|
|
26
|
+
# rspec-expectations config goes here. You can use an alternate
|
27
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
28
|
+
# assertions if you prefer.
|
29
|
+
config.expect_with :rspec do |expectations|
|
30
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
31
|
+
# and `failure_message` of custom matchers include text for helper methods
|
32
|
+
# defined using `chain`, e.g.:
|
33
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
34
|
+
# # => "be bigger than 2 and smaller than 4"
|
35
|
+
# ...rather than:
|
36
|
+
# # => "be bigger than 2"
|
37
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
38
|
+
end
|
39
|
+
|
40
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
41
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
42
|
+
config.mock_with :rspec do |mocks|
|
43
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
44
|
+
# a real object. This is generally recommended, and will default to
|
45
|
+
# `true` in RSpec 4.
|
46
|
+
mocks.verify_partial_doubles = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# The settings below are suggested to provide a good initial experience
|
50
|
+
# with RSpec, but feel free to customize to your heart's content.
|
51
|
+
=begin
|
52
|
+
# These two settings work together to allow you to limit a spec run
|
53
|
+
# to individual examples or groups you care about by tagging them with
|
54
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
55
|
+
# get run.
|
56
|
+
config.filter_run :focus
|
57
|
+
config.run_all_when_everything_filtered = true
|
58
|
+
|
59
|
+
# Allows RSpec to persist some state between runs in order to support
|
60
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
61
|
+
# you configure your source control system to ignore this file.
|
62
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
63
|
+
|
64
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
65
|
+
# recommended. For more details, see:
|
66
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
67
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
68
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
69
|
+
config.disable_monkey_patching!
|
70
|
+
|
71
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
72
|
+
# be too noisy due to issues in dependencies.
|
73
|
+
config.warnings = true
|
74
|
+
|
75
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
76
|
+
# file, and it's useful to allow more verbose output when running an
|
77
|
+
# individual spec file.
|
78
|
+
if config.files_to_run.one?
|
79
|
+
# Use the documentation formatter for detailed output,
|
80
|
+
# unless a formatter has already been configured
|
81
|
+
# (e.g. via a command-line flag).
|
82
|
+
config.default_formatter = 'doc'
|
83
|
+
end
|
84
|
+
|
85
|
+
# Print the 10 slowest examples and example groups at the
|
86
|
+
# end of the spec run, to help surface which specs are running
|
87
|
+
# particularly slow.
|
88
|
+
config.profile_examples = 10
|
89
|
+
|
90
|
+
# Run specs in random order to surface order dependencies. If you find an
|
91
|
+
# order dependency and want to debug it, you can fix the order by providing
|
92
|
+
# the seed, which is printed after each run.
|
93
|
+
# --seed 1234
|
94
|
+
config.order = :random
|
95
|
+
|
96
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
97
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
98
|
+
# test failures related to randomization by passing the same `--seed` value
|
99
|
+
# as the one that triggered the failure.
|
100
|
+
Kernel.srand config.seed
|
101
|
+
=end
|
102
|
+
end
|