pastel 0.7.4 → 0.8.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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +26 -22
- data/lib/pastel.rb +17 -14
- data/lib/pastel/alias_importer.rb +6 -5
- data/lib/pastel/ansi.rb +1 -1
- data/lib/pastel/color.rb +52 -16
- data/lib/pastel/color_parser.rb +21 -19
- data/lib/pastel/color_resolver.rb +2 -2
- data/lib/pastel/decorator_chain.rb +47 -9
- data/lib/pastel/delegator.rb +53 -29
- data/lib/pastel/detached.rb +41 -7
- data/lib/pastel/version.rb +2 -2
- metadata +3 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '06693f6ff4f804468ff3802df48c725067fb8eb425e9ba4301627f7c496099bb'
|
4
|
+
data.tar.gz: 0752767e8bbe626d683e5eb8b576f5c1229c322f72475d41b1041f4f15eb2c11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2239724d8aa9165ec045a2f43b6b8ce336c35ad487bc9e5ca1a8005c0321c682a73fff711316710848fee9931790c47a72dc5469afda25e98975bf6c38a9dfc5
|
7
|
+
data.tar.gz: b8f59e4fa1c52973d91d41d4e3f8602da3b164a41125a7416c7f119f53f880e81f4d3a79ea52e25b4e9de4dcb338d37ff1045f9b7b4437056cb7dc1597ce87df
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.8.0] - 2020-07-04
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
* Change gemspec to require Ruby 2.0 or higher
|
7
|
+
* Change Pastel#new to use keyword arguments in place of hash options
|
8
|
+
* Change to freeze all strings
|
9
|
+
* Remove equatable dependency
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
* Fix Pastel#strip to recognise no-number reset by DanielVartanov(@DanielVartanov)
|
13
|
+
* Fix Pastel#undecorate to correctly assign styles for nested colors
|
14
|
+
|
3
15
|
## [v0.7.4] - 2020-05-08
|
4
16
|
|
5
17
|
### Fixed
|
@@ -122,6 +134,7 @@
|
|
122
134
|
* Change gemspec to include equatable as dependency
|
123
135
|
* Change Delegator to stop creating instances and improve performance
|
124
136
|
|
137
|
+
[v0.8.0]: https://github.com/piotrmurach/pastel/compare/v0.7.4...v0.8.0
|
125
138
|
[v0.7.4]: https://github.com/piotrmurach/pastel/compare/v0.7.3...v0.7.4
|
126
139
|
[v0.7.3]: https://github.com/piotrmurach/pastel/compare/v0.7.2...v0.7.3
|
127
140
|
[v0.7.2]: https://github.com/piotrmurach/pastel/compare/v0.7.1...v0.7.2
|
data/README.md
CHANGED
@@ -39,7 +39,7 @@
|
|
39
39
|
|
40
40
|
Add this line to your application's Gemfile:
|
41
41
|
|
42
|
-
gem
|
42
|
+
gem "pastel"
|
43
43
|
|
44
44
|
And then execute:
|
45
45
|
|
@@ -76,7 +76,7 @@ Or install it yourself as:
|
|
76
76
|
```ruby
|
77
77
|
pastel = Pastel.new
|
78
78
|
|
79
|
-
puts pastel.red(
|
79
|
+
puts pastel.red("Unicorns!")
|
80
80
|
```
|
81
81
|
|
82
82
|
**Pastel** doesn't print the colored string out, just returns it, you'll have to print it yourself.
|
@@ -84,46 +84,46 @@ puts pastel.red('Unicorns!')
|
|
84
84
|
You can compose multiple styles through chainable API:
|
85
85
|
|
86
86
|
```ruby
|
87
|
-
pastel.red.on_green.bold(
|
87
|
+
pastel.red.on_green.bold("Unicorns!")
|
88
88
|
```
|
89
89
|
|
90
90
|
It allows you to combine styled strings with unstyled ones:
|
91
91
|
|
92
92
|
```ruby
|
93
|
-
pastel.red(
|
93
|
+
pastel.red("Unicorns") + " will rule " + pastel.green("the World!")
|
94
94
|
```
|
95
95
|
|
96
96
|
It supports variable number of arguments:
|
97
97
|
|
98
98
|
```ruby
|
99
|
-
pastel.red(
|
99
|
+
pastel.red("Unicorns", "are", "running", "everywhere!")
|
100
100
|
```
|
101
101
|
|
102
102
|
You can also nest styles as follows:
|
103
103
|
|
104
104
|
```ruby
|
105
|
-
pastel.red(
|
105
|
+
pastel.red("Unicorns ", pastel.on_green("everywhere!"))
|
106
106
|
```
|
107
107
|
|
108
108
|
Nesting is smart enough to know where one color ends and another one starts:
|
109
109
|
|
110
110
|
```ruby
|
111
|
-
pastel.red(
|
111
|
+
pastel.red("Unicorns " + pastel.green("everywhere") + pastel.on_yellow("!"))
|
112
112
|
```
|
113
113
|
|
114
114
|
You can also nest styles inside blocks:
|
115
115
|
|
116
116
|
```ruby
|
117
|
-
pastel.red.on_green(
|
118
|
-
green.on_red(
|
119
|
-
yellow(
|
117
|
+
pastel.red.on_green("Unicorns") {
|
118
|
+
green.on_red("will ", "dominate") {
|
119
|
+
yellow("the world!")
|
120
120
|
}
|
121
121
|
}
|
122
122
|
```
|
123
123
|
|
124
124
|
When dealing with multiline strings you can set `eachline` option(more info see [eachline](#211-eachline)):
|
125
125
|
|
126
|
-
```
|
126
|
+
```ruby
|
127
127
|
pastel = Pastel.new(eachline: "\n")
|
128
128
|
```
|
129
129
|
|
@@ -133,8 +133,8 @@ You can also predefine needed styles and reuse them:
|
|
133
133
|
error = pastel.red.bold.detach
|
134
134
|
warning = pastel.yellow.detach
|
135
135
|
|
136
|
-
puts error.(
|
137
|
-
puts warning.(
|
136
|
+
puts error.("Error!")
|
137
|
+
puts warning.("Warning")
|
138
138
|
```
|
139
139
|
|
140
140
|
If your output is redirected to a file, you probably don't want Pastel to add color to your text.
|
@@ -143,7 +143,7 @@ See https://github.com/piotrmurach/pastel#210-enabled for a way to easily accomp
|
|
143
143
|
**Pastel** has companion library called `pastel-cli` that allows you to style text in terminal via `pastel` executable:
|
144
144
|
|
145
145
|
```bash
|
146
|
-
$ pastel green
|
146
|
+
$ pastel green "Unicorns & rainbows!"
|
147
147
|
```
|
148
148
|
|
149
149
|
## 2 Interface
|
@@ -155,7 +155,7 @@ pastel.`
|
|
155
155
|
Color styles are invoked as method calls with a string argument. A given color can take any number of strings as arguments. Then it returns a colored string which isn't printed out to terminal. You need to print it yourself if you need to. This is done so that you can save it as a string, pass to something else, send it to a file handle and so on.
|
156
156
|
|
157
157
|
```ruby
|
158
|
-
pastel.red(
|
158
|
+
pastel.red("Unicorns ", pastel.bold.underline("everywhere"), "!")
|
159
159
|
```
|
160
160
|
|
161
161
|
Please refer to [3. Supported Colors](#3-supported-colors) section for full list of supported styles.
|
@@ -165,7 +165,7 @@ Please refer to [3. Supported Colors](#3-supported-colors) section for full list
|
|
165
165
|
This method is a lower level string styling call that takes as the first argument the string to style followed by any number of color attributes, and returns string wrapped in styles.
|
166
166
|
|
167
167
|
```ruby
|
168
|
-
pastel.decorate(
|
168
|
+
pastel.decorate("Unicorn", :green, :on_blue, :bold)
|
169
169
|
```
|
170
170
|
|
171
171
|
This method will be useful in situations where colors are provided as a list of parameters that have been generated dynamically.
|
@@ -176,7 +176,7 @@ It performs the opposite to `decorate` method by turning color escape sequences
|
|
176
176
|
|
177
177
|
```ruby
|
178
178
|
pastel.undecorate("\e[32mfoo\e[0m \e[31mbar\e[0m")
|
179
|
-
# => [{foreground: :green, text:
|
179
|
+
# => [{foreground: :green, text: "foo"}, {text: " "}, {foreground: :red, text: "bar"}]
|
180
180
|
```
|
181
181
|
|
182
182
|
To translate the color name into sequence use [lookup](#27-lookup)
|
@@ -188,9 +188,9 @@ The `detach` method allows to keep all the associated colors with the detached i
|
|
188
188
|
```ruby
|
189
189
|
notice = pastel.blue.bold.detach
|
190
190
|
|
191
|
-
notice.call(
|
192
|
-
notice.(
|
193
|
-
notice[
|
191
|
+
notice.call("Unicorns running")
|
192
|
+
notice.("Unicorns running")
|
193
|
+
notice["Unicorns running"]
|
194
194
|
```
|
195
195
|
|
196
196
|
### 2.5 Strip
|
@@ -278,7 +278,7 @@ pastel.alias_color(:funky, :red, :bold)
|
|
278
278
|
From that point forward, `:funky` alias can be passed to `decorate`, `valid?` with the same meaning as standard colors:
|
279
279
|
|
280
280
|
```ruby
|
281
|
-
pastel.funky.on_green(
|
281
|
+
pastel.funky.on_green("unicorn") # => will use :red, :bold color
|
282
282
|
```
|
283
283
|
|
284
284
|
This method allows you to give more meaningful names to existing colors.
|
@@ -351,7 +351,7 @@ This environment variable allows you to specify custom color aliases at runtime
|
|
351
351
|
Only alphanumeric and `_` and `.` are allowed in the alias names with the following format:
|
352
352
|
|
353
353
|
```ruby
|
354
|
-
PASTEL_COLORS_ALIASES=
|
354
|
+
PASTEL_COLORS_ALIASES="newcolor_1=red,newcolor_2=on_green,funky=red.bold"
|
355
355
|
```
|
356
356
|
|
357
357
|
## 5. Command line
|
@@ -370,6 +370,10 @@ $ pastel green 'Unicorns & rainbows!'
|
|
370
370
|
4. Push to the branch (`git push origin my-new-feature`)
|
371
371
|
5. Create a new Pull Request
|
372
372
|
|
373
|
+
## Code of Conduct
|
374
|
+
|
375
|
+
Everyone interacting in the Pastel project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/pastel/blob/master/CODE_OF_CONDUCT.md).
|
376
|
+
|
373
377
|
## Copyright
|
374
378
|
|
375
379
|
Copyright (c) 2014 Piotr Murach. See LICENSE for further details.
|
data/lib/pastel.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "tty-color"
|
4
4
|
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative 'pastel/version'
|
5
|
+
require_relative "pastel/alias_importer"
|
6
|
+
require_relative "pastel/color"
|
7
|
+
require_relative "pastel/color_resolver"
|
8
|
+
require_relative "pastel/delegator"
|
9
|
+
require_relative "pastel/version"
|
11
10
|
|
12
11
|
module Pastel
|
13
12
|
# Raised when the style attribute is not supported
|
@@ -21,19 +20,23 @@ module Pastel
|
|
21
20
|
# @example
|
22
21
|
# pastel = Pastel.new enabled: true
|
23
22
|
#
|
23
|
+
# @param [Boolean] :enabled
|
24
|
+
# whether or not to disable coloring
|
25
|
+
# @param [Boolean] :eachline
|
26
|
+
# whether or not to wrap eachline with separate coloring
|
27
|
+
#
|
24
28
|
# @return [Delegator]
|
25
29
|
#
|
26
30
|
# @api public
|
27
|
-
def new(
|
28
|
-
|
29
|
-
|
31
|
+
def new(enabled: nil, eachline: false)
|
32
|
+
if enabled.nil?
|
33
|
+
enabled = (TTY::Color.windows? || TTY::Color.color?)
|
30
34
|
end
|
31
|
-
color = Color.new(
|
35
|
+
color = Color.new(enabled: enabled, eachline: eachline)
|
32
36
|
importer = AliasImporter.new(color, ENV)
|
33
37
|
importer.import
|
34
38
|
resolver = ColorResolver.new(color)
|
35
|
-
Delegator.
|
39
|
+
Delegator.wrap(resolver)
|
36
40
|
end
|
37
|
-
|
38
41
|
module_function :new
|
39
42
|
end # Pastel
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Pastel
|
4
4
|
# A class responsible for importing color aliases
|
@@ -25,15 +25,16 @@ module Pastel
|
|
25
25
|
#
|
26
26
|
# @api public
|
27
27
|
def import
|
28
|
-
color_aliases = env[
|
28
|
+
color_aliases = env["PASTEL_COLORS_ALIASES"]
|
29
29
|
return unless color_aliases
|
30
|
-
|
31
|
-
|
30
|
+
|
31
|
+
color_aliases.split(",").each do |color_alias|
|
32
|
+
new_color, old_colors = color_alias.split("=")
|
32
33
|
if !new_color || !old_colors
|
33
34
|
output.puts "Bad color mapping `#{color_alias}`"
|
34
35
|
else
|
35
36
|
color.alias_color(new_color.to_sym,
|
36
|
-
*old_colors.split(
|
37
|
+
*old_colors.split(".").map(&:to_sym))
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
data/lib/pastel/ansi.rb
CHANGED
data/lib/pastel/color.rb
CHANGED
@@ -1,32 +1,29 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require_relative 'ansi'
|
3
|
+
require_relative "ansi"
|
6
4
|
|
7
5
|
module Pastel
|
8
6
|
# A class responsible for coloring strings.
|
9
7
|
class Color
|
10
|
-
include Equatable
|
11
8
|
include ANSI
|
12
9
|
|
13
10
|
# All color aliases
|
14
11
|
ALIASES = {}
|
15
12
|
|
16
13
|
# Match all color escape sequences
|
17
|
-
ANSI_COLOR_REGEXP = /\x1b
|
14
|
+
ANSI_COLOR_REGEXP = /\x1b\[{1,2}[0-9;:?]*m/mo.freeze
|
18
15
|
|
19
16
|
attr_reader :enabled
|
20
|
-
|
17
|
+
alias enabled? enabled
|
21
18
|
|
22
19
|
attr_reader :eachline
|
23
20
|
|
24
21
|
# Initialize a Terminal Color
|
25
22
|
#
|
26
23
|
# @api public
|
27
|
-
def initialize(
|
28
|
-
@enabled =
|
29
|
-
@eachline =
|
24
|
+
def initialize(enabled: nil, eachline: false)
|
25
|
+
@enabled = enabled
|
26
|
+
@eachline = eachline
|
30
27
|
@cache = {}
|
31
28
|
end
|
32
29
|
|
@@ -104,7 +101,7 @@ module Pastel
|
|
104
101
|
#
|
105
102
|
# @api public
|
106
103
|
def strip(*strings)
|
107
|
-
modified = strings.map { |string| string.dup.gsub(ANSI_COLOR_REGEXP,
|
104
|
+
modified = strings.map { |string| string.dup.gsub(ANSI_COLOR_REGEXP, "") }
|
108
105
|
modified.size == 1 ? modified[0] : modified
|
109
106
|
end
|
110
107
|
|
@@ -210,16 +207,54 @@ module Pastel
|
|
210
207
|
validate(*colors)
|
211
208
|
|
212
209
|
if !(alias_name.to_s =~ /^[\w]+$/)
|
213
|
-
|
210
|
+
raise InvalidAliasNameError, "Invalid alias name `#{alias_name}`"
|
214
211
|
elsif ANSI::ATTRIBUTES[alias_name]
|
215
|
-
|
216
|
-
|
212
|
+
raise InvalidAliasNameError,
|
213
|
+
"Cannot alias standard color `#{alias_name}`"
|
217
214
|
end
|
218
215
|
|
219
216
|
ALIASES[alias_name.to_sym] = colors.map(&ANSI::ATTRIBUTES.method(:[]))
|
220
217
|
colors
|
221
218
|
end
|
222
219
|
|
220
|
+
# Compare colors for equality of attributes
|
221
|
+
#
|
222
|
+
# @return [Boolean]
|
223
|
+
#
|
224
|
+
# @api public
|
225
|
+
def eql?(other)
|
226
|
+
instance_of?(other.class) &&
|
227
|
+
enabled.eql?(other.enabled) && eachline.eql?(other.eachline)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Compare colors for equivalence of attributes
|
231
|
+
#
|
232
|
+
# @return [Boolean]
|
233
|
+
#
|
234
|
+
# @api public
|
235
|
+
def ==(other)
|
236
|
+
other.is_a?(self.class) &&
|
237
|
+
enabled == other.enabled && eachline == other.eachline
|
238
|
+
end
|
239
|
+
|
240
|
+
# Inspect this instance attributes
|
241
|
+
#
|
242
|
+
# @return [String]
|
243
|
+
#
|
244
|
+
# @api public
|
245
|
+
def inspect
|
246
|
+
"#<#{self.class.name} enabled=#{enabled.inspect} eachline=#{eachline.inspect}>"
|
247
|
+
end
|
248
|
+
|
249
|
+
# Hash for this instance and its attributes
|
250
|
+
#
|
251
|
+
# @return [Numeric]
|
252
|
+
#
|
253
|
+
# @api public
|
254
|
+
def hash
|
255
|
+
[self.class, enabled, eachline].hash
|
256
|
+
end
|
257
|
+
|
223
258
|
private
|
224
259
|
|
225
260
|
# Check if value contains anything to style
|
@@ -228,13 +263,14 @@ module Pastel
|
|
228
263
|
#
|
229
264
|
# @api private
|
230
265
|
def blank?(value)
|
231
|
-
value.nil? || !value.respond_to?(:to_str) || value.to_s ==
|
266
|
+
value.nil? || !value.respond_to?(:to_str) || value.to_s == ""
|
232
267
|
end
|
233
268
|
|
234
269
|
# @api private
|
235
270
|
def validate(*colors)
|
236
271
|
return if valid?(*colors)
|
237
|
-
|
272
|
+
|
273
|
+
raise InvalidAttributeNameError, "Bad style or unintialized constant, " \
|
238
274
|
" valid styles are: #{style_names.join(', ')}."
|
239
275
|
end
|
240
276
|
end # Color
|
data/lib/pastel/color_parser.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "strscan"
|
4
4
|
|
5
|
-
require_relative
|
5
|
+
require_relative "ansi"
|
6
6
|
|
7
7
|
module Pastel
|
8
8
|
# Responsible for parsing color symbols out of text with color escapes
|
@@ -13,15 +13,16 @@ module Pastel
|
|
13
13
|
class ColorParser
|
14
14
|
include ANSI
|
15
15
|
|
16
|
-
ESC = "\x1b"
|
17
|
-
CSI = "\["
|
16
|
+
ESC = "\x1b"
|
17
|
+
CSI = "\["
|
18
18
|
|
19
19
|
# Parse color escape sequences into a list of hashes
|
20
20
|
# corresponding to the color attributes being set by these
|
21
21
|
# sequences
|
22
22
|
#
|
23
23
|
# @example
|
24
|
-
# parse("\e[32mfoo\e[0m")
|
24
|
+
# parse("\e[32mfoo\e[0m")
|
25
|
+
# # => [{foreground: :green, text: "foo"}
|
25
26
|
#
|
26
27
|
# @param [String] text
|
27
28
|
# the text to parse for presence of color ansi codes
|
@@ -34,20 +35,19 @@ module Pastel
|
|
34
35
|
state = {}
|
35
36
|
result = []
|
36
37
|
ansi_stack = []
|
37
|
-
text_chunk =
|
38
|
+
text_chunk = []
|
38
39
|
|
39
40
|
until scanner.eos?
|
40
41
|
char = scanner.getch
|
41
42
|
# match control
|
42
43
|
if char == ESC && (delim = scanner.getch) == CSI
|
43
|
-
if scanner.scan(/^
|
44
|
+
if scanner.scan(/^0?m/) # reset
|
44
45
|
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
|
45
46
|
ansi_stack = []
|
46
47
|
elsif scanner.scan(/^([1-9;:]+)m/)
|
47
48
|
# ansi codes separated by text
|
48
49
|
if !text_chunk.empty? && !ansi_stack.empty?
|
49
50
|
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
|
50
|
-
ansi_stack = []
|
51
51
|
end
|
52
52
|
scanner[1].split(/:|;/).each do |code|
|
53
53
|
ansi_stack << code
|
@@ -55,10 +55,10 @@ module Pastel
|
|
55
55
|
end
|
56
56
|
|
57
57
|
if !text_chunk.empty?
|
58
|
-
state[:text] = text_chunk
|
58
|
+
state[:text] = text_chunk.join
|
59
59
|
result.push(state)
|
60
60
|
state = {}
|
61
|
-
text_chunk
|
61
|
+
text_chunk.clear
|
62
62
|
end
|
63
63
|
elsif char == ESC # broken escape
|
64
64
|
text_chunk << char + delim.to_s
|
@@ -68,12 +68,12 @@ module Pastel
|
|
68
68
|
end
|
69
69
|
|
70
70
|
if !text_chunk.empty?
|
71
|
-
state[:text] = text_chunk
|
71
|
+
state[:text] = text_chunk.join
|
72
72
|
end
|
73
73
|
if !ansi_stack.empty?
|
74
74
|
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name}
|
75
75
|
end
|
76
|
-
if state.
|
76
|
+
if !state[:text].to_s.empty?
|
77
77
|
result.push(state)
|
78
78
|
end
|
79
79
|
result
|
@@ -88,10 +88,8 @@ module Pastel
|
|
88
88
|
#
|
89
89
|
# @api private
|
90
90
|
def self.unpack_ansi(ansi_stack)
|
91
|
-
ansi_stack.each do |
|
92
|
-
|
93
|
-
attr = attribute_for(ansi)
|
94
|
-
yield attr, name
|
91
|
+
ansi_stack.each do |code|
|
92
|
+
yield(attribute_name(code), color_name(code))
|
95
93
|
end
|
96
94
|
end
|
97
95
|
|
@@ -103,7 +101,7 @@ module Pastel
|
|
103
101
|
# @return [Symbol]
|
104
102
|
#
|
105
103
|
# @api private
|
106
|
-
def self.
|
104
|
+
def self.attribute_name(ansi)
|
107
105
|
if ANSI.foreground?(ansi)
|
108
106
|
:foreground
|
109
107
|
elsif ANSI.background?(ansi)
|
@@ -113,9 +111,13 @@ module Pastel
|
|
113
111
|
end
|
114
112
|
end
|
115
113
|
|
114
|
+
# Convert ANSI code to color name
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
#
|
116
118
|
# @api private
|
117
|
-
def self.
|
118
|
-
ATTRIBUTES.key(
|
119
|
+
def self.color_name(ansi_code)
|
120
|
+
ATTRIBUTES.key(ansi_code.to_i)
|
119
121
|
end
|
120
122
|
end # Parser
|
121
123
|
end # Pastel
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require 'equatable'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module Pastel
|
6
4
|
# Collects a list of decorators for styling a string
|
@@ -8,14 +6,27 @@ module Pastel
|
|
8
6
|
# @api private
|
9
7
|
class DecoratorChain
|
10
8
|
include Enumerable
|
11
|
-
include Equatable
|
12
9
|
|
13
|
-
|
10
|
+
# Create an empty decorator chain
|
11
|
+
#
|
12
|
+
# @return [DecoratorChain]
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def self.empty
|
16
|
+
@empty ||= self.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create a decorator chain
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def initialize(decorators = [].freeze)
|
14
23
|
@decorators = decorators
|
15
24
|
end
|
16
25
|
|
17
26
|
# Add decorator
|
18
27
|
#
|
28
|
+
# @param [String] decorator
|
29
|
+
#
|
19
30
|
# @api public
|
20
31
|
def add(decorator)
|
21
32
|
if decorators.include?(decorator)
|
@@ -32,13 +43,40 @@ module Pastel
|
|
32
43
|
decorators.each(&block)
|
33
44
|
end
|
34
45
|
|
35
|
-
#
|
46
|
+
# Compare colors for equality of attributes
|
36
47
|
#
|
37
|
-
# @return [
|
48
|
+
# @return [Boolean]
|
38
49
|
#
|
39
50
|
# @api public
|
40
|
-
def
|
41
|
-
|
51
|
+
def eql?(other)
|
52
|
+
instance_of?(other.class) && decorators.eql?(other.decorators)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Compare colors for equivalence of attributes
|
56
|
+
#
|
57
|
+
# @return [Boolean]
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def ==(other)
|
61
|
+
other.is_a?(self.class) && decorators == other.decorators
|
62
|
+
end
|
63
|
+
|
64
|
+
# Inspect this instance attributes
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def inspect
|
70
|
+
"#<#{self.class.name} decorators=#{decorators.inspect}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Hash for this instance and its attributes
|
74
|
+
#
|
75
|
+
# @return [Numeric]
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def hash
|
79
|
+
[self.class, decorators].hash
|
42
80
|
end
|
43
81
|
|
44
82
|
protected
|
data/lib/pastel/delegator.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'forwardable'
|
3
|
+
require "forwardable"
|
5
4
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
5
|
+
require_relative "color_parser"
|
6
|
+
require_relative "decorator_chain"
|
8
7
|
|
9
8
|
module Pastel
|
10
9
|
# Wrapes the {DecoratorChain} to allow for easy resolution
|
@@ -13,13 +12,19 @@ module Pastel
|
|
13
12
|
# @api private
|
14
13
|
class Delegator
|
15
14
|
extend Forwardable
|
16
|
-
include Equatable
|
17
15
|
|
18
|
-
def_delegators
|
16
|
+
def_delegators "@resolver.color", :valid?, :styles, :strip, :decorate,
|
19
17
|
:enabled?, :colored?, :alias_color, :lookup
|
20
18
|
|
21
19
|
def_delegators ColorParser, :parse
|
22
|
-
|
20
|
+
alias undecorate parse
|
21
|
+
|
22
|
+
# Wrap resolver and chain
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def self.wrap(resolver, chain = DecoratorChain.empty)
|
26
|
+
new(resolver, chain)
|
27
|
+
end
|
23
28
|
|
24
29
|
# Create Delegator
|
25
30
|
#
|
@@ -27,20 +32,31 @@ module Pastel
|
|
27
32
|
#
|
28
33
|
# @param [ColorResolver] resolver
|
29
34
|
#
|
30
|
-
# @param [DecoratorChain]
|
35
|
+
# @param [DecoratorChain] chain
|
31
36
|
#
|
32
37
|
# @api private
|
33
|
-
def initialize(resolver,
|
38
|
+
def initialize(resolver, chain)
|
34
39
|
@resolver = resolver
|
35
|
-
@
|
40
|
+
@chain = chain
|
36
41
|
end
|
37
42
|
|
43
|
+
# Compare delegated objects for equality of attributes
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
#
|
38
47
|
# @api public
|
39
|
-
def
|
40
|
-
|
48
|
+
def eql?(other)
|
49
|
+
instance_of?(other.class) && chain.eql?(other.chain)
|
41
50
|
end
|
42
51
|
|
43
|
-
|
52
|
+
# Compare delegated objects for equivalence of attributes
|
53
|
+
#
|
54
|
+
# @return [Boolean]
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def ==(other)
|
58
|
+
other.is_a?(self.class) && chain == other.chain
|
59
|
+
end
|
44
60
|
|
45
61
|
# Object string representation
|
46
62
|
#
|
@@ -48,35 +64,43 @@ module Pastel
|
|
48
64
|
#
|
49
65
|
# @api
|
50
66
|
def inspect
|
51
|
-
"#<Pastel
|
67
|
+
"#<Pastel styles=#{chain.map(&:to_s)}>"
|
68
|
+
end
|
69
|
+
alias to_s inspect
|
70
|
+
|
71
|
+
# Hash for this instance and its attributes
|
72
|
+
#
|
73
|
+
# @return [Numeric]
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
def hash
|
77
|
+
[self.class, chain].hash
|
52
78
|
end
|
53
|
-
alias_method :to_s, :inspect
|
54
79
|
|
55
80
|
protected
|
56
81
|
|
57
|
-
attr_reader :
|
82
|
+
attr_reader :chain
|
58
83
|
|
59
84
|
attr_reader :resolver
|
60
85
|
|
61
|
-
#
|
86
|
+
# Handles color method calls
|
62
87
|
#
|
63
88
|
# @api private
|
64
|
-
def wrap(base)
|
65
|
-
self.class.new(resolver, base)
|
66
|
-
end
|
67
|
-
|
68
89
|
def method_missing(method_name, *args, &block)
|
69
|
-
|
70
|
-
delegator = wrap(
|
71
|
-
if args.empty? &&
|
90
|
+
new_chain = chain.add(method_name)
|
91
|
+
delegator = self.class.wrap(resolver, new_chain)
|
92
|
+
if args.empty? && method_name.to_sym != :detach
|
72
93
|
delegator
|
73
94
|
else
|
74
|
-
|
75
|
-
|
76
|
-
resolver.resolve(
|
95
|
+
strings = args.dup
|
96
|
+
strings << evaluate_block(&block) if block_given?
|
97
|
+
resolver.resolve(new_chain, strings.join)
|
77
98
|
end
|
78
99
|
end
|
79
100
|
|
101
|
+
# Check if color is valid
|
102
|
+
#
|
103
|
+
# @api private
|
80
104
|
def respond_to_missing?(name, include_all = false)
|
81
105
|
resolver.color.respond_to?(name, include_all) ||
|
82
106
|
resolver.color.valid?(name) || super
|
@@ -86,7 +110,7 @@ module Pastel
|
|
86
110
|
#
|
87
111
|
# @api private
|
88
112
|
def evaluate_block(&block)
|
89
|
-
delegator = self.class.
|
113
|
+
delegator = self.class.wrap(resolver)
|
90
114
|
delegator.instance_eval(&block)
|
91
115
|
end
|
92
116
|
end # Delegator
|
data/lib/pastel/detached.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require 'equatable'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module Pastel
|
6
4
|
# A class representing detached color
|
7
5
|
class Detached
|
8
|
-
include Equatable
|
9
|
-
|
10
6
|
# Initialize a detached object
|
11
7
|
#
|
12
8
|
# @param [Pastel::Color] color
|
@@ -24,6 +20,8 @@ module Pastel
|
|
24
20
|
# Decorate the values corresponding to styles
|
25
21
|
#
|
26
22
|
# @example
|
23
|
+
# Detached(Color.new, :red, :bold).call("hello")
|
24
|
+
# # => "\e[31mhello\e[0m"
|
27
25
|
#
|
28
26
|
# @param [String] value
|
29
27
|
# the stirng to decorate with styles
|
@@ -35,14 +33,50 @@ module Pastel
|
|
35
33
|
value = args.join
|
36
34
|
@color.decorate(value, *styles)
|
37
35
|
end
|
38
|
-
|
36
|
+
alias [] call
|
39
37
|
|
40
38
|
# @api public
|
41
39
|
def to_proc
|
42
40
|
self
|
43
41
|
end
|
44
42
|
|
45
|
-
|
43
|
+
# Compare detached objects for equality of attributes
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def eql?(other)
|
49
|
+
instance_of?(other.class) && styles.eql?(other.styles)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Compare detached objects for equivalence of attributes
|
53
|
+
#
|
54
|
+
# @return [Boolean]
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def ==(other)
|
58
|
+
other.is_a?(self.class) && styles == other.styles
|
59
|
+
end
|
60
|
+
|
61
|
+
# Inspect this instance attributes
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def inspect
|
67
|
+
"#<#{self.class.name} styles=#{styles.inspect}>"
|
68
|
+
end
|
69
|
+
|
70
|
+
# Hash for this instance and its attributes
|
71
|
+
#
|
72
|
+
# @return [Numeric]
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
def hash
|
76
|
+
[self.class, styles].hash
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
46
80
|
|
47
81
|
# @api private
|
48
82
|
attr_reader :styles
|
data/lib/pastel/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pastel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: equatable
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0.6'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0.6'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: tty-color
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
93
|
requirements:
|
108
94
|
- - ">="
|
109
95
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
96
|
+
version: 2.0.0
|
111
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
98
|
requirements:
|
113
99
|
- - ">="
|