pastel 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f27ae640e6ef241eef25aa65ca531e0bf2b77242c3575c217a50c6679146ca7a
4
- data.tar.gz: 87d9af402543b3094c16c233aecaaeea8bf9e418bf1b5b3f04d09998e576c69c
3
+ metadata.gz: '06693f6ff4f804468ff3802df48c725067fb8eb425e9ba4301627f7c496099bb'
4
+ data.tar.gz: 0752767e8bbe626d683e5eb8b576f5c1229c322f72475d41b1041f4f15eb2c11
5
5
  SHA512:
6
- metadata.gz: a1b38a5b8437adf408d6308b96389a846a81e1a13e34446db4b75ce06b37f54f08d05706e8a2505916a29d8e6ee025ca58528676ad978eaee30bd3af0a0eee04
7
- data.tar.gz: b43aad885a8d33ff9e9f2ec5abcfbee59dfef0fce1f62c54628190e8196881ca7bbcad76a2af99fdb5d16a02cb161f1045da5763db6825c1f53a8c152bc8e663
6
+ metadata.gz: 2239724d8aa9165ec045a2f43b6b8ce336c35ad487bc9e5ca1a8005c0321c682a73fff711316710848fee9931790c47a72dc5469afda25e98975bf6c38a9dfc5
7
+ data.tar.gz: b8f59e4fa1c52973d91d41d4e3f8602da3b164a41125a7416c7f119f53f880e81f4d3a79ea52e25b4e9de4dcb338d37ff1045f9b7b4437056cb7dc1597ce87df
@@ -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 'pastel'
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('Unicorns!')
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('Unicorns!')
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('Unicorns') + ' will rule ' + pastel.green('the World!')
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('Unicorns', 'are', 'running', 'everywhere!')
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('Unicorns ', pastel.on_green('everywhere!'))
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('Unicorns ' + pastel.green('everywhere') + pastel.on_yellow('!'))
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('Unicorns') {
118
- green.on_red('will ', 'dominate') {
119
- yellow('the world!')
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.('Error!')
137
- puts warning.('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 'Unicorns & rainbows!'
146
+ $ pastel green "Unicorns & rainbows!"
147
147
  ```
148
148
 
149
149
  ## 2 Interface
@@ -155,7 +155,7 @@ pastel.`[....](string, [string...])`
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('Unicorns ', pastel.bold.underline('everywhere'), '!')
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('Unicorn', :green, :on_blue, :bold)
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: 'foo'}, {text: ' '}, {foreground: :red, text: 'bar'}]
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('Unicorns running')
192
- notice.('Unicorns running')
193
- notice['Unicorns running']
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('unicorn') # => will use :red, :bold color
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='newcolor_1=red,newcolor_2=on_green,funky=red.bold'
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.
@@ -1,13 +1,12 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'tty-color'
3
+ require "tty-color"
4
4
 
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/decorator_chain'
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(options = {})
28
- unless options.key?(:enabled)
29
- options[:enabled] = (TTY::Color.windows? || TTY::Color.color?)
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(options)
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.for(resolver, DecoratorChain.empty)
39
+ Delegator.wrap(resolver)
36
40
  end
37
-
38
41
  module_function :new
39
42
  end # Pastel
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
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['PASTEL_COLORS_ALIASES']
28
+ color_aliases = env["PASTEL_COLORS_ALIASES"]
29
29
  return unless color_aliases
30
- color_aliases.split(',').each do |color_alias|
31
- new_color, old_colors = color_alias.split('=')
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('.').map(&:to_sym))
37
+ *old_colors.split(".").map(&:to_sym))
37
38
  end
38
39
  end
39
40
  end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Pastel
4
4
  # Mixin that provides ANSI codes
@@ -1,32 +1,29 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'equatable'
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+(\[|\[\[)[0-9;:?]+m/mo.freeze
14
+ ANSI_COLOR_REGEXP = /\x1b\[{1,2}[0-9;:?]*m/mo.freeze
18
15
 
19
16
  attr_reader :enabled
20
- alias_method :enabled?, :enabled
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(options = {})
28
- @enabled = options[:enabled]
29
- @eachline = options.fetch(:eachline) { false }
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
- fail InvalidAliasNameError, "Invalid alias name `#{alias_name}`"
210
+ raise InvalidAliasNameError, "Invalid alias name `#{alias_name}`"
214
211
  elsif ANSI::ATTRIBUTES[alias_name]
215
- fail InvalidAliasNameError,
216
- "Cannot alias standard color `#{alias_name}`"
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
- fail InvalidAttributeNameError, 'Bad style or unintialized constant, ' \
272
+
273
+ raise InvalidAttributeNameError, "Bad style or unintialized constant, " \
238
274
  " valid styles are: #{style_names.join(', ')}."
239
275
  end
240
276
  end # Color
@@ -1,8 +1,8 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require "strscan"
4
4
 
5
- require_relative 'ansi'
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".freeze
17
- CSI = "\[".freeze
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") # => [{colors: [:green], text: 'foo'}
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(/^0m/)
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.values.any? { |val| !val.empty? }
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 |ansi|
92
- name = ansi_for(ansi)
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.attribute_for(ansi)
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.ansi_for(ansi)
118
- ATTRIBUTES.key(ansi.to_i)
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,6 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require_relative 'detached'
3
+ require_relative "detached"
4
4
 
5
5
  module Pastel
6
6
  # Contains logic for resolving styles applied to component
@@ -1,6 +1,4 @@
1
- # coding: utf-8
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
- def initialize(decorators = [])
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
- # Create an empty decorator chain
46
+ # Compare colors for equality of attributes
36
47
  #
37
- # @return [DecoratorChain]
48
+ # @return [Boolean]
38
49
  #
39
50
  # @api public
40
- def self.empty
41
- new([])
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
@@ -1,10 +1,9 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'equatable'
4
- require 'forwardable'
3
+ require "forwardable"
5
4
 
6
- require_relative 'color_parser'
7
- require_relative 'decorator_chain'
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 '@resolver.color', :valid?, :styles, :strip, :decorate,
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
- alias_method :undecorate, :parse
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] base
35
+ # @param [DecoratorChain] chain
31
36
  #
32
37
  # @api private
33
- def initialize(resolver, base)
38
+ def initialize(resolver, chain)
34
39
  @resolver = resolver
35
- @base = base
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 self.for(resolver, base)
40
- new(resolver, base)
48
+ def eql?(other)
49
+ instance_of?(other.class) && chain.eql?(other.chain)
41
50
  end
42
51
 
43
- remove_method :inspect
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 @styles=#{base.map(&:to_s)}>"
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 :base
82
+ attr_reader :chain
58
83
 
59
84
  attr_reader :resolver
60
85
 
61
- # Wrap colors
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
- new_base = base.add(method_name)
70
- delegator = wrap(new_base)
71
- if args.empty? && !(method_name.to_sym == :detach)
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
- string = args.join
75
- string << evaluate_block(&block) if block_given?
76
- resolver.resolve(new_base, string)
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.new(resolver, DecoratorChain.empty)
113
+ delegator = self.class.wrap(resolver)
90
114
  delegator.instance_eval(&block)
91
115
  end
92
116
  end # Delegator
@@ -1,12 +1,8 @@
1
- # encoding: utf-8
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
- alias_method :[], :call
36
+ alias [] call
39
37
 
40
38
  # @api public
41
39
  def to_proc
42
40
  self
43
41
  end
44
42
 
45
- private
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
@@ -1,5 +1,5 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Pastel
4
- VERSION = '0.7.4'
4
+ VERSION = "0.8.0"
5
5
  end
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.7.4
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-05-08 00:00:00.000000000 Z
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: '0'
96
+ version: 2.0.0
111
97
  required_rubygems_version: !ruby/object:Gem::Requirement
112
98
  requirements:
113
99
  - - ">="