sai 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sai/decorator.rb CHANGED
@@ -1,30 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'sai'
3
4
  require 'sai/ansi'
5
+ require 'sai/ansi/sequenced_string'
4
6
  require 'sai/conversion/color_sequence'
5
7
 
6
8
  module Sai
7
9
  # A decorator for applying ANSI styles and colors to text
8
10
  #
9
11
  # @author {https://aaronmallen.me Aaron Allen}
10
- # @since unreleased
12
+ # @since 0.1.0
11
13
  #
12
14
  # @api public
13
15
  class Decorator
14
16
  # Initialize a new instance of Decorator
15
17
  #
16
18
  # @author {https://aaronmallen.me Aaron Allen}
17
- # @since unreleased
19
+ # @since 0.1.0
18
20
  #
19
21
  # @api private
20
22
  #
21
- # @param color_mode [Integer] the color mode to use
23
+ # @param mode [Integer] the color mode to use
22
24
  #
23
25
  # @return [Decorator] the new instance of Decorator
24
- # @rbs (Integer color_mode) -> void
25
- def initialize(color_mode)
26
+ # @rbs (?mode: Integer) -> void
27
+ def initialize(mode: Sai.mode.auto)
26
28
  @background = nil
27
- @color_mode = color_mode
29
+ @mode = mode
28
30
  @foreground = nil
29
31
  @styles = [] #: Array[Symbol]
30
32
  end
@@ -33,40 +35,40 @@ module Sai
33
35
  # Apply the named ANSI color "black" to the foreground
34
36
  #
35
37
  # @author {https://aaronmallen.me Aaron Allen}
36
- # @since unreleased
38
+ # @since 0.1.0
37
39
  #
38
40
  # @api public
39
41
  #
40
42
  # @example
41
- # decorator.black.decorate('Hello, world!') #=> "\e[30mHello, world!\e[0m"
43
+ # decorator.black.decorate('Hello, world!').to_s #=> "\e[30mHello, world!\e[0m"
42
44
  #
43
- # @return [self] the instance of Decorator for chaining
45
+ # @return [Decorator] a new instance of Decorator with the color applied
44
46
  #
45
47
  # @!method blue
46
48
  # Apply the named ANSI color "blue" to the foreground
47
49
  #
48
50
  # @author {https://aaronmallen.me Aaron Allen}
49
- # @since unreleased
51
+ # @since 0.1.0
50
52
  #
51
53
  # @api public
52
54
  #
53
55
  # @example
54
- # decorator.blue.decorate('Hello, world!') #=> "\e[34mHello, world!\e[0m"
56
+ # decorator.blue.decorate('Hello, world!').to_s #=> "\e[34mHello, world!\e[0m"
55
57
  #
56
- # @return [self] the instance of Decorator for chaining
58
+ # @return [Decorator] a new instance of Decorator with the color applied
57
59
  #
58
60
  # @!method bright_black
59
61
  # Apply the named ANSI color "bright_black" to the foreground
60
62
  #
61
63
  # @author {https://aaronmallen.me Aaron Allen}
62
- # @since unreleased
64
+ # @since 0.1.0
63
65
  #
64
66
  # @api public
65
67
  #
66
68
  # @example
67
- # decorator.bright_black.decorate('Hello, world!') #=> "\e[90mHello, world!\e[0m"
69
+ # decorator.bright_black.decorate('Hello, world!').to_s #=> "\e[90mHello, world!\e[0m"
68
70
  #
69
- # @return [self] the instance of Decorator for chaining
71
+ # @return [Decorator] a new instance of Decorator with the color applied
70
72
  #
71
73
  # @!method bright_blue
72
74
  # Apply the named ANSI color "bright_blue" to the foreground
@@ -74,9 +76,9 @@ module Sai
74
76
  # @api public
75
77
  #
76
78
  # @example
77
- # decorator.bright_blue.decorate('Hello, world!') #=> "\e[94mHello, world!\e[0m"
79
+ # decorator.bright_blue.decorate('Hello, world!').to_s #=> "\e[94mHello, world!\e[0m"
78
80
  #
79
- # @return [self] the instance of Decorator for chaining
81
+ # @return [Decorator] a new instance of Decorator with the color applied
80
82
  #
81
83
  # @!method bright_cyan
82
84
  # Apply the named ANSI color "bright_cyan" to the foreground
@@ -84,9 +86,9 @@ module Sai
84
86
  # @api public
85
87
  #
86
88
  # @example
87
- # decorator.bright_cyan.decorate('Hello, world!') #=> "\e[96mHello, world!\e[0m"
89
+ # decorator.bright_cyan.decorate('Hello, world!').to_s #=> "\e[96mHello, world!\e[0m"
88
90
  #
89
- # @return [self] the instance of Decorator for chaining
91
+ # @return [Decorator] a new instance of Decorator with the color applied
90
92
  #
91
93
  # @!method bright_green
92
94
  # Apply the named ANSI color "bright_green" to the foreground
@@ -94,9 +96,9 @@ module Sai
94
96
  # @api public
95
97
  #
96
98
  # @example
97
- # decorator.bright_green.decorate('Hello, world!') #=> "\e[92mHello, world!\e[0m"
99
+ # decorator.bright_green.decorate('Hello, world!').to_s #=> "\e[92mHello, world!\e[0m"
98
100
  #
99
- # @return [self] the instance of Decorator for chaining
101
+ # @return [Decorator] a new instance of Decorator with the color applied
100
102
  #
101
103
  # @!method bright_magenta
102
104
  # Apply the named ANSI color "bright_magenta" to the foreground
@@ -104,9 +106,9 @@ module Sai
104
106
  # @api public
105
107
  #
106
108
  # @example
107
- # decorator.bright_magenta.decorate('Hello, world!') #=> "\e[95mHello, world!\e[0m"
109
+ # decorator.bright_magenta.decorate('Hello, world!').to_s #=> "\e[95mHello, world!\e[0m"
108
110
  #
109
- # @return [self] the instance of Decorator for chaining
111
+ # @return [Decorator] a new instance of Decorator with the color applied
110
112
  #
111
113
  # @!method bright_red
112
114
  # Apply the named ANSI color "bright_red" to the foreground
@@ -114,9 +116,9 @@ module Sai
114
116
  # @api public
115
117
  #
116
118
  # @example
117
- # decorator.bright_red.decorate('Hello, world!') #=> "\e[91mHello, world!\e[0m"
119
+ # decorator.bright_red.decorate('Hello, world!').to_s #=> "\e[91mHello, world!\e[0m"
118
120
  #
119
- # @return [self] the instance of Decorator for chaining
121
+ # @return [Decorator] a new instance of Decorator with the color applied
120
122
  #
121
123
  # @!method bright_white
122
124
  # Apply the named ANSI color "bright_white" to the foreground
@@ -124,9 +126,9 @@ module Sai
124
126
  # @api public
125
127
  #
126
128
  # @example
127
- # decorator.bright_white.decorate('Hello, world!') #=> "\e[97mHello, world!\e[0m"
129
+ # decorator.bright_white.decorate('Hello, world!').to_s #=> "\e[97mHello, world!\e[0m"
128
130
  #
129
- # @return [self] the instance of Decorator for chaining
131
+ # @return [Decorator] a new instance of Decorator with the color applied
130
132
  #
131
133
  # @!method bright_yellow
132
134
  # Apply the named ANSI color "bright_yellow" to the foreground
@@ -134,9 +136,9 @@ module Sai
134
136
  # @api public
135
137
  #
136
138
  # @example
137
- # decorator.bright_yellow.decorate('Hello, world!') #=> "\e[93mHello, world!\e[0m"
139
+ # decorator.bright_yellow.decorate('Hello, world!').to_s #=> "\e[93mHello, world!\e[0m"
138
140
  #
139
- # @return [self] the instance of Decorator for chaining
141
+ # @return [Decorator] a new instance of Decorator with the color applied
140
142
  #
141
143
  # @!method cyan
142
144
  # Apply the named ANSI color "cyan" to the foreground
@@ -144,9 +146,9 @@ module Sai
144
146
  # @api public
145
147
  #
146
148
  # @example
147
- # decorator.cyan.decorate('Hello, world!') #=> "\e[36mHello, world!\e[0m"
149
+ # decorator.cyan.decorate('Hello, world!').to_s #=> "\e[36mHello, world!\e[0m"
148
150
  #
149
- # @return [self] the instance of Decorator for chaining
151
+ # @return [Decorator] a new instance of Decorator with the color applied
150
152
  #
151
153
  # @!method green
152
154
  # Apply the named ANSI color "green" to the foreground
@@ -154,9 +156,9 @@ module Sai
154
156
  # @api public
155
157
  #
156
158
  # @example
157
- # decorator.green.decorate('Hello, world!') #=> "\e[32mHello, world!\e[0m"
159
+ # decorator.green.decorate('Hello, world!').to_s #=> "\e[32mHello, world!\e[0m"
158
160
  #
159
- # @return [self] the instance of Decorator for chaining
161
+ # @return [Decorator] a new instance of Decorator with the color applied
160
162
  #
161
163
  # @!method magenta
162
164
  # Apply the named ANSI color "magenta" to the foreground
@@ -164,217 +166,217 @@ module Sai
164
166
  # @api public
165
167
  #
166
168
  # @example
167
- # decorator.magenta.decorate('Hello, world!') #=> "\e[35mHello, world!\e[0m"
169
+ # decorator.magenta.decorate('Hello, world!').to_s #=> "\e[35mHello, world!\e[0m"
168
170
  #
169
- # @return [self] the instance of Decorator for chaining
171
+ # @return [Decorator] a new instance of Decorator with the color applied
170
172
  #
171
173
  # @!method on_black
172
174
  # Apply the named ANSI color "black" to the background
173
175
  #
174
176
  # @author {https://aaronmallen.me Aaron Allen}
175
- # @since unreleased
177
+ # @since 0.1.0
176
178
  #
177
179
  # @api public
178
180
  #
179
181
  # @example
180
- # decorator.on_black.decorate('Hello, world!') #=> "\e[40mHello, world!\e[0m"
182
+ # decorator.on_black.decorate('Hello, world!').to_s #=> "\e[40mHello, world!\e[0m"
181
183
  #
182
- # @return [self] the instance of Decorator for chaining
184
+ # @return [Decorator] a new instance of Decorator with the color applied
183
185
  #
184
186
  # @!method on_blue
185
187
  # Apply the named ANSI color "blue" to the background
186
188
  #
187
189
  # @author {https://aaronmallen.me Aaron Allen}
188
- # @since unreleased
190
+ # @since 0.1.0
189
191
  #
190
192
  # @api public
191
193
  #
192
194
  # @example
193
- # decorator.on_blue.decorate('Hello, world!') #=> "\e[44mHello, world!\e[0m"
195
+ # decorator.on_blue.decorate('Hello, world!').to_s #=> "\e[44mHello, world!\e[0m"
194
196
  #
195
- # @return [self] the instance of Decorator for chaining
197
+ # @return [Decorator] a new instance of Decorator with the color applied
196
198
  #
197
199
  # @!method on_bright_black
198
200
  # Apply the named ANSI color "bright_black" to the background
199
201
  #
200
202
  # @author {https://aaronmallen.me Aaron Allen}
201
- # @since unreleased
203
+ # @since 0.1.0
202
204
  #
203
205
  # @api public
204
206
  #
205
207
  # @example
206
- # decorator.on_bright_black.decorate('Hello, world!') #=> "\e[100mHello, world!\e[0m"
208
+ # decorator.on_bright_black.decorate('Hello, world!').to_s #=> "\e[100mHello, world!\e[0m"
207
209
  #
208
- # @return [self] the instance of Decorator for chaining
210
+ # @return [Decorator] a new instance of Decorator with the color applied
209
211
  #
210
212
  # @!method on_bright_blue
211
213
  # Apply the named ANSI color "bright_blue" to the background
212
214
  #
213
215
  # @author {https://aaronmallen.me Aaron Allen}
214
- # @since unreleased
216
+ # @since 0.1.0
215
217
  #
216
218
  # @api public
217
219
  #
218
220
  # @example
219
- # decorator.on_bright_blue.decorate('Hello, world!') #=> "\e[104mHello, world!\e[0m"
221
+ # decorator.on_bright_blue.decorate('Hello, world!').to_s #=> "\e[104mHello, world!\e[0m"
220
222
  #
221
- # @return [self] the instance of Decorator for chaining
223
+ # @return [Decorator] a new instance of Decorator with the color applied
222
224
  #
223
225
  # @!method on_bright_cyan
224
226
  # Apply the named ANSI color "bright_cyan" to the background
225
227
  #
226
228
  # @author {https://aaronmallen.me Aaron Allen}
227
- # @since unreleased
229
+ # @since 0.1.0
228
230
  #
229
231
  # @api public
230
232
  #
231
233
  # @example
232
- # decorator.on_bright_cyan.decorate('Hello, world!') #=> "\e[106mHello, world!\e[0m"
234
+ # decorator.on_bright_cyan.decorate('Hello, world!').to_s #=> "\e[106mHello, world!\e[0m"
233
235
  #
234
- # @return [self] the instance of Decorator for chaining
236
+ # @return [Decorator] a new instance of Decorator with the color applied
235
237
  #
236
238
  # @!method on_bright_green
237
239
  # Apply the named ANSI color "bright_green" to the background
238
240
  #
239
241
  # @author {https://aaronmallen.me Aaron Allen}
240
- # @since unreleased
242
+ # @since 0.1.0
241
243
  #
242
244
  # @api public
243
245
  #
244
246
  # @example
245
- # decorator.on_bright_green.decorate('Hello, world!') #=> "\e[102mHello, world!\e[0m"
247
+ # decorator.on_bright_green.decorate('Hello, world!').to_s #=> "\e[102mHello, world!\e[0m"
246
248
  #
247
- # @return [self] the instance of Decorator for chaining
249
+ # @return [Decorator] a new instance of Decorator with the color applied
248
250
  #
249
251
  # @!method on_bright_magenta
250
252
  # Apply the named ANSI color "bright_magenta" to the background
251
253
  #
252
254
  # @author {https://aaronmallen.me Aaron Allen}
253
- # @since unreleased
255
+ # @since 0.1.0
254
256
  #
255
257
  # @api public
256
258
  #
257
259
  # @example
258
- # decorator.on_bright_magenta.decorate('Hello, world!') #=> "\e[105mHello, world!\e[0m"
260
+ # decorator.on_bright_magenta.decorate('Hello, world!').to_s #=> "\e[105mHello, world!\e[0m"
259
261
  #
260
- # @return [self] the instance of Decorator for chaining
262
+ # @return [Decorator] a new instance of Decorator with the color applied
261
263
  #
262
264
  # @!method on_bright_red
263
265
  # Apply the named ANSI color "bright_red" to the background
264
266
  #
265
267
  # @author {https://aaronmallen.me Aaron Allen}
266
- # @since unreleased
268
+ # @since 0.1.0
267
269
  #
268
270
  # @api public
269
271
  #
270
272
  # @example
271
- # decorator.on_bright_red.decorate('Hello, world!') #=> "\e[101mHello, world!\e[0m"
273
+ # decorator.on_bright_red.decorate('Hello, world!').to_s #=> "\e[101mHello, world!\e[0m"
272
274
  #
273
- # @return [self] the instance of Decorator for chaining
275
+ # @return [Decorator] a new instance of Decorator with the color applied
274
276
  #
275
277
  # @!method on_bright_white
276
278
  # Apply the named ANSI color "bright_white" to the background
277
279
  #
278
280
  # @author {https://aaronmallen.me Aaron Allen}
279
- # @since unreleased
281
+ # @since 0.1.0
280
282
  #
281
283
  # @api public
282
284
  #
283
285
  # @example
284
- # decorator.on_bright_white.decorate('Hello, world!') #=> "\e[107mHello, world!\e[0m"
286
+ # decorator.on_bright_white.decorate('Hello, world!').to_s #=> "\e[107mHello, world!\e[0m"
285
287
  #
286
- # @return [self] the instance of Decorator for chaining
288
+ # @return [Decorator] a new instance of Decorator with the color applied
287
289
  #
288
290
  # @!method on_bright_yellow
289
291
  # Apply the named ANSI color "bright_yellow" to the background
290
292
  #
291
293
  # @author {https://aaronmallen.me Aaron Allen}
292
- # @since unreleased
294
+ # @since 0.1.0
293
295
  #
294
296
  # @api public
295
297
  #
296
298
  # @example
297
- # decorator.on_bright_yellow.decorate('Hello, world!') #=> "\e[103mHello, world!\e[0m"
299
+ # decorator.on_bright_yellow.decorate('Hello, world!').to_s #=> "\e[103mHello, world!\e[0m"
298
300
  #
299
- # @return [self] the instance of Decorator for chaining
301
+ # @return [Decorator] a new instance of Decorator with the color applied
300
302
  #
301
303
  # @!method on_cyan
302
304
  # Apply the named ANSI color "cyan" to the background
303
305
  #
304
306
  # @author {https://aaronmallen.me Aaron Allen}
305
- # @since unreleased
307
+ # @since 0.1.0
306
308
  #
307
309
  # @api public
308
310
  #
309
311
  # @example
310
- # decorator.on_cyan.decorate('Hello, world!') #=> "\e[46mHello, world!\e[0m"
312
+ # decorator.on_cyan.decorate('Hello, world!').to_s #=> "\e[46mHello, world!\e[0m"
311
313
  #
312
- # @return [self] the instance of Decorator for chaining
314
+ # @return [Decorator] a new instance of Decorator with the color applied
313
315
  #
314
316
  # @!method on_green
315
317
  # Apply the named ANSI color "green" to the background
316
318
  #
317
319
  # @author {https://aaronmallen.me Aaron Allen}
318
- # @since unreleased
320
+ # @since 0.1.0
319
321
  #
320
322
  # @api public
321
323
  #
322
324
  # @example
323
- # decorator.on_green.decorate('Hello, world!') #=> "\e[42mHello, world!\e[0m"
325
+ # decorator.on_green.decorate('Hello, world!').to_s #=> "\e[42mHello, world!\e[0m"
324
326
  #
325
- # @return [self] the instance of Decorator for chaining
327
+ # @return [Decorator] a new instance of Decorator with the color applied
326
328
  #
327
329
  # @!method on_magenta
328
330
  # Apply the named ANSI color "magenta" to the background
329
331
  #
330
332
  # @author {https://aaronmallen.me Aaron Allen}
331
- # @since unreleased
333
+ # @since 0.1.0
332
334
  #
333
335
  # @api public
334
336
  #
335
337
  # @example
336
- # decorator.on_magenta.decorate('Hello, world!') #=> "\e[45mHello, world!\e[0m"
338
+ # decorator.on_magenta.decorate('Hello, world!').to_s #=> "\e[45mHello, world!\e[0m"
337
339
  #
338
- # @return [self] the instance of Decorator for chaining
340
+ # @return [Decorator] a new instance of Decorator with the color applied
339
341
  #
340
342
  # @!method on_red
341
343
  # Apply the named ANSI color "red" to the background
342
344
  #
343
345
  # @author {https://aaronmallen.me Aaron Allen}
344
- # @since unreleased
346
+ # @since 0.1.0
345
347
  #
346
348
  # @api public
347
349
  #
348
350
  # @example
349
- # decorator.on_red.decorate('Hello, world!') #=> "\e[41mHello, world!\e[0m"
351
+ # decorator.on_red.decorate('Hello, world!').to_s #=> "\e[41mHello, world!\e[0m"
350
352
  #
351
- # @return [self] the instance of Decorator for chaining
353
+ # @return [Decorator] a new instance of Decorator with the color applied
352
354
  #
353
355
  # @!method on_white
354
356
  # Apply the named ANSI color "white" to the background
355
357
  #
356
358
  # @author {https://aaronmallen.me Aaron Allen}
357
- # @since unreleased
359
+ # @since 0.1.0
358
360
  #
359
361
  # @api public
360
362
  #
361
363
  # @example
362
- # decorator.on_white.decorate('Hello, world!') #=> "\e[47mHello, world!\e[0m"
364
+ # decorator.on_white.decorate('Hello, world!').to_s #=> "\e[47mHello, world!\e[0m"
363
365
  #
364
- # @return [self] the instance of Decorator for chaining
366
+ # @return [Decorator] a new instance of Decorator with the color applied
365
367
  #
366
368
  # @!method on_yellow
367
369
  # Apply the named ANSI color "yellow" to the background
368
370
  #
369
371
  # @author {https://aaronmallen.me Aaron Allen}
370
- # @since unreleased
372
+ # @since 0.1.0
371
373
  #
372
374
  # @api public
373
375
  #
374
376
  # @example
375
- # decorator.on_yellow.decorate('Hello, world!') #=> "\e[43mHello, world!\e[0m"
377
+ # decorator.on_yellow.decorate('Hello, world!').to_s #=> "\e[43mHello, world!\e[0m"
376
378
  #
377
- # @return [self] the instance of Decorator for chaining
379
+ # @return [Decorator] a new instance of Decorator with the color applied
378
380
  #
379
381
  # @!method red
380
382
  # Apply the named ANSI color "red" to the foreground
@@ -382,9 +384,9 @@ module Sai
382
384
  # @api public
383
385
  #
384
386
  # @example
385
- # decorator.red.decorate('Hello, world!') #=> "\e[31mHello, world!\e[0m"
387
+ # decorator.red.decorate('Hello, world!').to_s #=> "\e[31mHello, world!\e[0m"
386
388
  #
387
- # @return [self] the instance of Decorator for chaining
389
+ # @return [Decorator] a new instance of Decorator with the color applied
388
390
  #
389
391
  # @!method white
390
392
  # Apply the named ANSI color "white" to the foreground
@@ -392,9 +394,9 @@ module Sai
392
394
  # @api public
393
395
  #
394
396
  # @example
395
- # decorator.white.decorate('Hello, world!') #=> "\e[37mHello, world!\e[0m"
397
+ # decorator.white.decorate('Hello, world!').to_s #=> "\e[37mHello, world!\e[0m"
396
398
  #
397
- # @return [self] the instance of Decorator for chaining
399
+ # @return [Decorator] a new instance of Decorator with the color applied
398
400
  #
399
401
  # @!method yellow
400
402
  # Apply the named ANSI color "yellow" to the foreground
@@ -402,9 +404,9 @@ module Sai
402
404
  # @api public
403
405
  #
404
406
  # @example
405
- # decorator.yellow.decorate('Hello, world!') #=> "\e[33mHello, world!\e[0m"
407
+ # decorator.yellow.decorate('Hello, world!').to_s #=> "\e[33mHello, world!\e[0m"
406
408
  #
407
- # @return [self] the instance of Decorator for chaining
409
+ # @return [Decorator] a new instance of Decorator with the color applied
408
410
  ANSI::COLOR_NAMES.each_key do |color|
409
411
  define_method(color) do
410
412
  apply_named_color(:foreground, color)
@@ -414,246 +416,246 @@ module Sai
414
416
  end
415
417
  end
416
418
  # @rbs!
417
- # def black: () -> self
418
- # def blue: () -> self
419
- # def bright_black: () -> self
420
- # def bright_blue: () -> self
421
- # def bright_cyan: () -> self
422
- # def bright_green: () -> self
423
- # def bright_magenta: () -> self
424
- # def bright_red: () -> self
425
- # def bright_white: () -> self
426
- # def bright_yellow: () -> self
427
- # def cyan: () -> self
428
- # def green: () -> self
429
- # def magenta: () -> self
430
- # def on_black: () -> self
431
- # def on_blue: () -> self
432
- # def on_bright_black: () -> self
433
- # def on_bright_blue: () -> self
434
- # def on_bright_cyan: () -> self
435
- # def on_bright_green: () -> self
436
- # def on_bright_magenta: () -> self
437
- # def on_bright_red: () -> self
438
- # def on_bright_white: () -> self
439
- # def on_bright_yellow: () -> self
440
- # def on_cyan: () -> self
441
- # def on_green: () -> self
442
- # def on_magenta: () -> self
443
- # def on_red: () -> self
444
- # def on_white: () -> self
445
- # def on_yellow: () -> self
446
- # def red: () -> self
447
- # def white: () -> self
448
- # def yellow: () -> self
419
+ # def black: () -> Decorator
420
+ # def blue: () -> Decorator
421
+ # def bright_black: () -> Decorator
422
+ # def bright_blue: () -> Decorator
423
+ # def bright_cyan: () -> Decorator
424
+ # def bright_green: () -> Decorator
425
+ # def bright_magenta: () -> Decorator
426
+ # def bright_red: () -> Decorator
427
+ # def bright_white: () -> Decorator
428
+ # def bright_yellow: () -> Decorator
429
+ # def cyan: () -> Decorator
430
+ # def green: () -> Decorator
431
+ # def magenta: () -> Decorator
432
+ # def on_black: () -> Decorator
433
+ # def on_blue: () -> Decorator
434
+ # def on_bright_black: () -> Decorator
435
+ # def on_bright_blue: () -> Decorator
436
+ # def on_bright_cyan: () -> Decorator
437
+ # def on_bright_green: () -> Decorator
438
+ # def on_bright_magenta: () -> Decorator
439
+ # def on_bright_red: () -> Decorator
440
+ # def on_bright_white: () -> Decorator
441
+ # def on_bright_yellow: () -> Decorator
442
+ # def on_cyan: () -> Decorator
443
+ # def on_green: () -> Decorator
444
+ # def on_magenta: () -> Decorator
445
+ # def on_red: () -> Decorator
446
+ # def on_white: () -> Decorator
447
+ # def on_yellow: () -> Decorator
448
+ # def red: () -> Decorator
449
+ # def white: () -> Decorator
450
+ # def yellow: () -> Decorator
449
451
 
450
452
  # @!method blink
451
453
  # Apply the ANSI style "blink" to the text
452
454
  #
453
455
  # @author {https://aaronmallen.me Aaron Allen}
454
- # @since unreleased
456
+ # @since 0.1.0
455
457
  #
456
458
  # @api public
457
459
  #
458
460
  # @example
459
- # decorator.blink.decorate('Hello, world!') #=> "\e[5mHello, world!\e[0m"
461
+ # decorator.blink.decorate('Hello, world!').to_s #=> "\e[5mHello, world!\e[0m"
460
462
  #
461
- # @return [self] the instance of Decorator for chaining
463
+ # @return [Decorator] a new instance of Decorator with the style applied
462
464
  #
463
465
  # @!method bold
464
466
  # Apply the ANSI style "bold" to the text
465
467
  #
466
468
  # @author {https://aaronmallen.me Aaron Allen}
467
- # @since unreleased
469
+ # @since 0.1.0
468
470
  #
469
471
  # @api public
470
472
  #
471
473
  # @example
472
- # decorator.bold.decorate('Hello, world!') #=> "\e[1mHello, world!\e[0m"
474
+ # decorator.bold.decorate('Hello, world!').to_s #=> "\e[1mHello, world!\e[0m"
473
475
  #
474
- # @return [self] the instance of Decorator for chaining
476
+ # @return [Decorator] a new instance of Decorator with the style applied
475
477
  #
476
478
  # @!method conceal
477
479
  # Apply the ANSI style "conceal" to the text
478
480
  #
479
481
  # @author {https://aaronmallen.me Aaron Allen}
480
- # @since unreleased
482
+ # @since 0.1.0
481
483
  #
482
484
  # @api public
483
485
  #
484
486
  # @example
485
- # decorator.conceal.decorate('Hello, world!') #=> "\e[8mHello, world!\e[0m"
487
+ # decorator.conceal.decorate('Hello, world!').to_s #=> "\e[8mHello, world!\e[0m"
486
488
  #
487
- # @return [self] the instance of Decorator for chaining
489
+ # @return [Decorator] a new instance of Decorator with the style applied
488
490
  #
489
491
  # @!method dim
490
492
  # Apply the ANSI style "dim" to the text
491
493
  #
492
494
  # @author {https://aaronmallen.me Aaron Allen}
493
- # @since unreleased
495
+ # @since 0.1.0
494
496
  #
495
497
  # @api public
496
498
  #
497
499
  # @example
498
- # decorator.dim.decorate('Hello, world!') #=> "\e[2mHello, world!\e[0m"
500
+ # decorator.dim.decorate('Hello, world!').to_s #=> "\e[2mHello, world!\e[0m"
499
501
  #
500
- # @return [self] the instance of Decorator for chaining
502
+ # @return [Decorator] a new instance of Decorator with the style applied
501
503
  #
502
504
  # @!method italic
503
505
  # Apply the ANSI style "italic" to the text
504
506
  #
505
507
  # @author {https://aaronmallen.me Aaron Allen}
506
- # @since unreleased
508
+ # @since 0.1.0
507
509
  #
508
510
  # @api public
509
511
  #
510
512
  # @example
511
- # decorator.italic.decorate('Hello, world!') #=> "\e[3mHello, world!\e[0m"
513
+ # decorator.italic.decorate('Hello, world!').to_s #=> "\e[3mHello, world!\e[0m"
512
514
  #
513
- # @return [self] the instance of Decorator for chaining
515
+ # @return [Decorator] a new instance of Decorator with the style applied
514
516
  #
515
517
  # @!method no_blink
516
518
  # Remove the ANSI style "blink" from the text
517
519
  #
518
520
  # @author {https://aaronmallen.me Aaron Allen}
519
- # @since unreleased
521
+ # @since 0.1.0
520
522
  #
521
523
  # @api public
522
524
  #
523
525
  # @example
524
- # decorator.no_blink.decorate('Hello, world!') #=> "\e[25mHello, world!\e[0m"
526
+ # decorator.no_blink.decorate('Hello, world!').to_s #=> "\e[25mHello, world!\e[0m"
525
527
  #
526
- # @return [self] the instance of Decorator for chaining
528
+ # @return [Decorator] a new instance of Decorator with the style applied
527
529
  #
528
530
  # @!method no_conceal
529
531
  # Remove the ANSI style "conceal" from the text
530
532
  #
531
533
  # @author {https://aaronmallen.me Aaron Allen}
532
- # @since unreleased
534
+ # @since 0.1.0
533
535
  #
534
536
  # @api public
535
537
  #
536
538
  # @example
537
- # decorator.no_conceal.decorate('Hello, world!') #=> "\e[28mHello, world!\e[0m"
539
+ # decorator.no_conceal.decorate('Hello, world!').to_s #=> "\e[28mHello, world!\e[0m"
538
540
  #
539
- # @return [self] the instance of Decorator for chaining
541
+ # @return [Decorator] a new instance of Decorator with the style applied
540
542
  #
541
543
  # @!method no_italic
542
544
  # Remove the ANSI style "italic" from the text
543
545
  #
544
546
  # @author {https://aaronmallen.me Aaron Allen}
545
- # @since unreleased
547
+ # @since 0.1.0
546
548
  #
547
549
  # @api public
548
550
  #
549
551
  # @example
550
- # decorator.no_italic.decorate('Hello, world!') #=> "\e[23mHello, world!\e[0m"
552
+ # decorator.no_italic.decorate('Hello, world!').to_s #=> "\e[23mHello, world!\e[0m"
551
553
  #
552
- # @return [self] the instance of Decorator for chaining
554
+ # @return [Decorator] a new instance of Decorator with the style applied
553
555
  #
554
556
  # @!method no_reverse
555
557
  # Remove the ANSI style "reverse" from the text
556
558
  #
557
559
  # @author {https://aaronmallen.me Aaron Allen}
558
- # @since unreleased
560
+ # @since 0.1.0
559
561
  #
560
562
  # @api public
561
563
  #
562
564
  # @example
563
- # decorator.no_reverse.decorate('Hello, world!') #=> "\e[27mHello, world!\e[0m"
565
+ # decorator.no_reverse.decorate('Hello, world!').to_s #=> "\e[27mHello, world!\e[0m"
564
566
  #
565
- # @return [self] the instance of Decorator for chaining
567
+ # @return [Decorator] a new instance of Decorator with the style applied
566
568
  #
567
569
  # @!method no_strike
568
570
  # Remove the ANSI style "strike" from the text
569
571
  #
570
572
  # @author {https://aaronmallen.me Aaron Allen}
571
- # @since unreleased
573
+ # @since 0.1.0
572
574
  #
573
575
  # @api public
574
576
  #
575
577
  # @example
576
- # decorator.no_strike.decorate('Hello, world!') #=> "\e[29mHello, world!\e[0m"
578
+ # decorator.no_strike.decorate('Hello, world!').to_s #=> "\e[29mHello, world!\e[0m"
577
579
  #
578
- # @return [self] the instance of Decorator for chaining
580
+ # @return [Decorator] a new instance of Decorator with the style applied
579
581
  #
580
582
  # @!method no_underline
581
583
  # Remove the ANSI style "underline" from the text
582
584
  #
583
585
  # @author {https://aaronmallen.me Aaron Allen}
584
- # @since unreleased
586
+ # @since 0.1.0
585
587
  #
586
588
  # @api public
587
589
  #
588
590
  # @example
589
- # decorator.no_underline.decorate('Hello, world!') #=> "\e[24mHello, world!\e[0m"
591
+ # decorator.no_underline.decorate('Hello, world!').to_s #=> "\e[24mHello, world!\e[0m"
590
592
  #
591
- # @return [self] the instance of Decorator for chaining
593
+ # @return [Decorator] a new instance of Decorator with the style applied
592
594
  #
593
595
  # @!method normal_intensity
594
596
  # Remove any intensity styles (bold or dim) from the text
595
597
  #
596
598
  # @author {https://aaronmallen.me Aaron Allen}
597
- # @since unreleased
599
+ # @since 0.1.0
598
600
  #
599
601
  # @api public
600
602
  #
601
603
  # @example
602
- # decorator.normal_intensity.decorate('Hello, world!') #=> "\e[22mHello, world!\e[0m"
604
+ # decorator.normal_intensity.decorate('Hello, world!').to_s #=> "\e[22mHello, world!\e[0m"
603
605
  #
604
- # @return [self] the instance of Decorator for chaining
606
+ # @return [Decorator] a new instance of Decorator with the style applied
605
607
  #
606
608
  # @!method rapid_blink
607
609
  # Apply the ANSI style "rapid_blink" to the text
608
610
  #
609
611
  # @author {https://aaronmallen.me Aaron Allen}
610
- # @since unreleased
612
+ # @since 0.1.0
611
613
  #
612
614
  # @api public
613
615
  #
614
616
  # @example
615
- # decorator.rapid_blink.decorate('Hello, world!') #=> "\e[6mHello, world!\e[0m"
617
+ # decorator.rapid_blink.decorate('Hello, world!').to_s #=> "\e[6mHello, world!\e[0m"
616
618
  #
617
- # @return [self] the instance of Decorator for chaining
619
+ # @return [Decorator] a new instance of Decorator with the style applied
618
620
  #
619
621
  # @!method reverse
620
622
  # Apply the ANSI style "reverse" to the text
621
623
  #
622
624
  # @author {https://aaronmallen.me Aaron Allen}
623
- # @since unreleased
625
+ # @since 0.1.0
624
626
  #
625
627
  # @api public
626
628
  #
627
629
  # @example
628
- # decorator.reverse.decorate('Hello, world!') #=> "\e[7mHello, world!\e[0m"
630
+ # decorator.reverse.decorate('Hello, world!').to_s #=> "\e[7mHello, world!\e[0m"
629
631
  #
630
- # @return [self] the instance of Decorator for chaining
632
+ # @return [Decorator] a new instance of Decorator with the style applied
631
633
  #
632
634
  # @!method strike
633
635
  # Apply the ANSI style "strike" to the text
634
636
  #
635
637
  # @author {https://aaronmallen.me Aaron Allen}
636
- # @since unreleased
638
+ # @since 0.1.0
637
639
  #
638
640
  # @api public
639
641
  #
640
642
  # @example
641
- # decorator.strike.decorate('Hello, world!') #=> "\e[9mHello, world!\e[0m"
643
+ # decorator.strike.decorate('Hello, world!').to_s #=> "\e[9mHello, world!\e[0m"
642
644
  #
643
- # @return [self] the instance of Decorator for chaining
645
+ # @return [Decorator] a new instance of Decorator with the style applied
644
646
  #
645
647
  # @!method underline
646
648
  # Apply the ANSI style "underline" to the text
647
649
  #
648
650
  # @author {https://aaronmallen.me Aaron Allen}
649
- # @since unreleased
651
+ # @since 0.1.0
650
652
  #
651
653
  # @api public
652
654
  #
653
655
  # @example
654
- # decorator.underline.decorate('Hello, world!') #=> "\e[4mHello, world!\e[0m"
656
+ # decorator.underline.decorate('Hello, world!').to_s #=> "\e[4mHello, world!\e[0m"
655
657
  #
656
- # @return [self] the instance of Decorator for chaining
658
+ # @return [Decorator] a new instance of Decorator with the style applied
657
659
  ANSI::STYLES.each_key do |style|
658
660
  define_method(style) do
659
661
  apply_style(style)
@@ -661,48 +663,47 @@ module Sai
661
663
  end
662
664
 
663
665
  # @rbs!
664
- # def blink: () -> self
665
- # def bold: () -> self
666
- # def conceal: () -> self
667
- # def dim: () -> self
668
- # def italic: () -> self
669
- # def no_blink: () -> self
670
- # def no_conceal: () -> self
671
- # def no_italic: () -> self
672
- # def no_reverse: () -> self
673
- # def no_strike: () -> self
674
- # def no_underline: () -> self
675
- # def normal_intensity: () -> self
676
- # def rapid_blink: () -> self
677
- # def reverse: () -> self
678
- # def strike: () -> self
679
- # def underline: () -> self
666
+ # def blink: () -> Decorator
667
+ # def bold: () -> Decorator
668
+ # def conceal: () -> Decorator
669
+ # def dim: () -> Decorator
670
+ # def italic: () -> Decorator
671
+ # def no_blink: () -> Decorator
672
+ # def no_conceal: () -> Decorator
673
+ # def no_italic: () -> Decorator
674
+ # def no_reverse: () -> Decorator
675
+ # def no_strike: () -> Decorator
676
+ # def no_underline: () -> Decorator
677
+ # def normal_intensity: () -> Decorator
678
+ # def rapid_blink: () -> Decorator
679
+ # def reverse: () -> Decorator
680
+ # def strike: () -> Decorator
681
+ # def underline: () -> Decorator
680
682
 
681
683
  # Apply the styles and colors to the text
682
684
  #
683
685
  # @author {https://aaronmallen.me Aaron Allen}
684
- # @since unreleased
686
+ # @since 0.1.0
685
687
  #
686
688
  # @api public
687
689
  #
688
690
  # @example
689
- # decorator.red.on_blue.bold.decorate('Hello, world!')
690
- # #=> "\e[38;2;205;0;0m\e[48;2;0;0;238m\e[1mHello, world!\e[0m"
691
+ # decorator.red.on_blue.bold.decorate('Hello, world!').to_s #=> "\e[38;5;160;48;5;21;1mHello, world!\e[0m"
691
692
  #
692
693
  # @param text [String] the text to decorate
693
694
  #
694
- # @return [String] the decorated text
695
- # @rbs (String text) -> String
695
+ # @return [ANSI::SequencedString] the decorated text
696
+ # @rbs (String text) -> ANSI::SequencedString
696
697
  def decorate(text)
697
- return text if @foreground.nil? && @background.nil? && @styles.empty?
698
+ return ANSI::SequencedString.new(text) unless should_decorate?
698
699
 
699
700
  sequences = [
700
- @foreground && Conversion::ColorSequence.resolve(@foreground, @color_mode),
701
- @background && Conversion::ColorSequence.resolve(@background, @color_mode, :background),
701
+ @foreground && Conversion::ColorSequence.resolve(@foreground, @mode),
702
+ @background && Conversion::ColorSequence.resolve(@background, @mode, :background),
702
703
  @styles.map { |style| "\e[#{ANSI::STYLES[style]}m" }.join
703
704
  ].compact.join
704
705
 
705
- "#{sequences}#{text}#{ANSI::RESET}"
706
+ ANSI::SequencedString.new("#{sequences}#{text}#{ANSI::RESET}")
706
707
  end
707
708
  alias apply decorate
708
709
  alias call decorate
@@ -711,97 +712,111 @@ module Sai
711
712
  # Apply a hexadecimal color to the foreground
712
713
  #
713
714
  # @author {https://aaronmallen.me Aaron Allen}
714
- # @since unreleased
715
+ # @since 0.1.0
715
716
  #
716
717
  # @api public
717
718
  #
718
719
  # @example
719
- # decorator.hex("#EB4133").decorate('Hello, world!') #=> "\e[38;2;235;65;51mHello, world!\e[0m"
720
+ # decorator.hex("#EB4133").decorate('Hello, world!').to_s #=> "\e[38;2;235;65;51mHello, world!\e[0m"
720
721
  #
721
722
  # @param code [String] the hex color code
722
723
  #
723
724
  # @raise [ArgumentError] if the hex code is invalid
724
- # @return [self] the instance of Decorator for chaining
725
- # @rbs (String code) -> self
725
+ # @return [Decorator] a new instance of Decorator with the hex color applied
726
+ # @rbs (String code) -> Decorator
726
727
  def hex(code)
727
728
  raise ArgumentError, "Invalid hex color code: #{code}" unless /^#?([A-Fa-f0-9]{6})$/.match?(code)
728
729
 
729
- @foreground = code
730
- self
730
+ dup.tap { |duped| duped.instance_variable_set(:@foreground, code) }
731
731
  end
732
732
 
733
733
  # Apply a hexadecimal color to the background
734
734
  #
735
735
  # @author {https://aaronmallen.me Aaron Allen}
736
- # @since unreleased
736
+ # @since 0.1.0
737
737
  #
738
738
  # @api public
739
739
  #
740
740
  # @example
741
- # decorator.on_hex("#EB4133").decorate('Hello, world!') #=> "\e[48;2;235;65;51mHello, world!\e[0m"
741
+ # decorator.on_hex("#EB4133").decorate('Hello, world!').to_s #=> "\e[48;2;235;65;51mHello, world!\e[0m"
742
742
  #
743
743
  # @param code [String] the hex color code
744
744
  #
745
745
  # @raise [ArgumentError] if the hex code is invalid
746
- # @return [self] the instance of Decorator for chaining
747
- # @rbs (String code) -> self
746
+ # @return [Decorator] a new instance of Decorator with the hex color applied
747
+ # @rbs (String code) -> Decorator
748
748
  def on_hex(code)
749
749
  raise ArgumentError, "Invalid hex color code: #{code}" unless /^#?([A-Fa-f0-9]{6})$/.match?(code)
750
750
 
751
- @background = code
752
- self
751
+ dup.tap { |duped| duped.instance_variable_set(:@background, code) }
753
752
  end
754
753
 
755
754
  # Apply an RGB color to the background
756
755
  #
757
756
  # @author {https://aaronmallen.me Aaron Allen}
758
- # @since unreleased
757
+ # @since 0.1.0
759
758
  #
760
759
  # @api public
761
760
  #
762
761
  # @example
763
- # decorator.on_rgb(235, 65, 51).decorate('Hello, world!') #=> "\e[48;2;235;65;51mHello, world!\e[0m"
762
+ # decorator.on_rgb(235, 65, 51).decorate('Hello, world!').to_s #=> "\e[48;2;235;65;51mHello, world!\e[0m"
764
763
  #
765
764
  # @param red [Integer] the red component
766
765
  # @param green [Integer] the green component
767
766
  # @param blue [Integer] the blue component
768
767
  #
769
768
  # @raise [ArgumentError] if the RGB values are out of range
770
- # @return [self] the instance of Decorator for chaining
771
- # @rbs (Integer red, Integer green, Integer blue) -> self
769
+ # @return [Decorator] a new instance of Decorator with the RGB color applied
770
+ # @rbs (Integer red, Integer green, Integer blue) -> Decorator
772
771
  def on_rgb(red, green, blue)
773
772
  [red, green, blue].each do |value|
774
773
  raise ArgumentError, "Invalid RGB value: #{red}, #{green}, #{blue}" unless value >= 0 && value <= 255
775
774
  end
776
775
 
777
- @background = [red, green, blue]
778
- self
776
+ dup.tap { |duped| duped.instance_variable_set(:@background, [red, green, blue]) }
779
777
  end
780
778
 
781
779
  # Apply an RGB color to the foreground
782
780
  #
783
781
  # @author {https://aaronmallen.me Aaron Allen}
784
- # @since unreleased
782
+ # @since 0.1.0
785
783
  #
786
784
  # @api public
787
785
  #
788
786
  # @example
789
- # decorator.rgb(235, 65, 51).decorate('Hello, world!') #=> "\e[38;2;235;65;51mHello, world!\e[0m"
787
+ # decorator.rgb(235, 65, 51).decorate('Hello, world!').to_s #=> "\e[38;2;235;65;51mHello, world!\e[0m"
790
788
  #
791
789
  # @param red [Integer] the red component
792
790
  # @param green [Integer] the green component
793
791
  # @param blue [Integer] the blue component
794
792
  #
795
793
  # @raise [ArgumentError] if the RGB values are out of range
796
- # @return [self] the instance of Decorator for chaining
797
- # @rbs (Integer red, Integer green, Integer blue) -> self
794
+ # @return [Decorator] a new instance of Decorator with the RGB color applied
795
+ # @rbs (Integer red, Integer green, Integer blue) -> Decorator
798
796
  def rgb(red, green, blue)
799
797
  [red, green, blue].each do |value|
800
798
  raise ArgumentError, "Invalid RGB value: #{red}, #{green}, #{blue}" unless value >= 0 && value <= 255
801
799
  end
802
800
 
803
- @foreground = [red, green, blue]
804
- self
801
+ dup.tap { |duped| duped.instance_variable_set(:@foreground, [red, green, blue]) }
802
+ end
803
+
804
+ # Apply a specific color mode to the decorator
805
+ #
806
+ # @author {https://aaronmallen.me Aaron Allen}
807
+ # @since 0.2.0
808
+ #
809
+ # @api public
810
+ #
811
+ # @example
812
+ # decorator.with_mode(Sai.mode.basic_auto) #=> => #<Sai::Decorator:0x123 @mode=1>
813
+ #
814
+ # @param mode [Integer] the color mode to use
815
+ #
816
+ # @return [Decorator] a new instance of Decorator with the applied color mode
817
+ # @rbs (Integer mode) -> Decorator
818
+ def with_mode(mode)
819
+ dup.tap { |duped| duped.instance_variable_set(:@mode, mode) }
805
820
  end
806
821
 
807
822
  private
@@ -809,48 +824,49 @@ module Sai
809
824
  # Apply a named color to the specified style type
810
825
  #
811
826
  # @author {https://aaronmallen.me Aaron Allen}
812
- # @since unreleased
827
+ # @since 0.1.0
813
828
  #
814
829
  # @api private
815
830
  #
816
831
  # @param style_type [Symbol] the style type to apply the color to
817
832
  # @param color [Symbol] the color to apply
818
833
  #
819
- # @raise [ArgumentError] if the color is invalid
820
- # @return [self] the instance of Decorator for chaining
821
- # @rbs (Conversion::ColorSequence::style_type style_type, Symbol color) -> self
834
+ # @return [Decorator] a new instance of Decorator with the color applied
835
+ # @rbs (Conversion::ColorSequence::style_type style_type, Symbol color) -> Decorator
822
836
  def apply_named_color(style_type, color)
823
- unless ANSI::COLOR_NAMES.key?(color.to_s.downcase.to_sym)
824
- e = ArgumentError.new("Invalid color: #{color}")
825
- e.set_backtrace(caller_locations(1, 1)&.map(&:to_s)) # steep:ignore UnresolvedOverloading
826
- raise e
827
- end
828
-
829
- instance_variable_set(:"@#{style_type}", color)
830
- self
837
+ dup.tap { |duped| duped.instance_variable_set(:"@#{style_type}", color) }
831
838
  end
832
839
 
833
840
  # Apply a style to the text
834
841
  #
835
842
  # @author {https://aaronmallen.me Aaron Allen}
836
- # @since unreleased
843
+ # @since 0.1.0
837
844
  #
838
845
  # @api private
839
846
  #
840
847
  # @param style [String, Symbol] the style to apply
841
848
  #
842
- # @raise [ArgumentError] if the style is invalid
843
- # @return [self] the instance of Decorator for chaining
849
+ # @return [Decorator] a new instance of Decorator with the style applied
844
850
  # @rbs (String | Symbol style) -> self
845
851
  def apply_style(style)
846
- unless ANSI::STYLES.key?(style.to_s.downcase.to_sym)
847
- e = ArgumentError.new("Invalid style: #{style}")
848
- e.set_backtrace(caller_locations(1, 1)&.map(&:to_s)) # steep:ignore UnresolvedOverloading
849
- raise e
850
- end
852
+ style = style.to_s.downcase.to_sym
853
+ dup.tap { |duped| duped.instance_variable_set(:@styles, (@styles + [style]).uniq) }
854
+ end
855
+
856
+ # Check if text should be decorated
857
+ #
858
+ # @author {https://aaronmallen.me Aaron Allen}
859
+ # @since 0.2.0
860
+ #
861
+ # @api private
862
+ #
863
+ # @return [Boolean] `true` if text should be decorated, `false` otherwise
864
+ # @rbs () -> bool
865
+ def should_decorate?
866
+ return false if @mode == Terminal::ColorMode::NO_COLOR
867
+ return false if @foreground.nil? && @background.nil? && @styles.empty?
851
868
 
852
- @styles = @styles.push(style.to_s.downcase.to_sym).uniq
853
- self
869
+ true
854
870
  end
855
871
  end
856
872
  end