pastel 0.7.0 → 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.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +57 -13
  3. data/README.md +36 -29
  4. data/lib/pastel.rb +17 -19
  5. data/lib/pastel/alias_importer.rb +9 -7
  6. data/lib/pastel/ansi.rb +2 -2
  7. data/lib/pastel/color.rb +63 -23
  8. data/lib/pastel/color_parser.rb +24 -18
  9. data/lib/pastel/color_resolver.rb +3 -1
  10. data/lib/pastel/decorator_chain.rb +47 -7
  11. data/lib/pastel/delegator.rb +57 -26
  12. data/lib/pastel/detached.rb +41 -5
  13. data/lib/pastel/version.rb +2 -2
  14. metadata +27 -97
  15. data/.gitignore +0 -22
  16. data/.rspec +0 -3
  17. data/.travis.yml +0 -26
  18. data/Gemfile +0 -16
  19. data/Rakefile +0 -8
  20. data/appveyor.yml +0 -23
  21. data/assets/pastel_logo.png +0 -0
  22. data/assets/screenshot.png +0 -0
  23. data/benchmarks/nesting_speed.rb +0 -41
  24. data/benchmarks/speed.rb +0 -45
  25. data/examples/palette.rb +0 -14
  26. data/pastel.gemspec +0 -26
  27. data/spec/spec_helper.rb +0 -45
  28. data/spec/unit/alias_color_spec.rb +0 -24
  29. data/spec/unit/alias_importer_spec.rb +0 -29
  30. data/spec/unit/color/alias_color_spec.rb +0 -40
  31. data/spec/unit/color/code_spec.rb +0 -24
  32. data/spec/unit/color/colored_spec.rb +0 -15
  33. data/spec/unit/color/decorate_spec.rb +0 -79
  34. data/spec/unit/color/equal_spec.rb +0 -22
  35. data/spec/unit/color/lookup_spec.rb +0 -17
  36. data/spec/unit/color/new_spec.rb +0 -10
  37. data/spec/unit/color/strip_spec.rb +0 -56
  38. data/spec/unit/color/styles_spec.rb +0 -10
  39. data/spec/unit/color/valid_spec.rb +0 -19
  40. data/spec/unit/color_parser_spec.rb +0 -67
  41. data/spec/unit/decorate_dsl_spec.rb +0 -98
  42. data/spec/unit/decorator_chain_spec.rb +0 -47
  43. data/spec/unit/delegator_spec.rb +0 -38
  44. data/spec/unit/detach_spec.rb +0 -48
  45. data/spec/unit/new_spec.rb +0 -63
  46. data/spec/unit/respond_to_spec.rb +0 -17
  47. data/spec/unit/undecorate_spec.rb +0 -12
  48. data/tasks/console.rake +0 -11
  49. data/tasks/coverage.rake +0 -11
  50. data/tasks/spec.rake +0 -29
@@ -1,4 +1,8 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ require_relative "ansi"
2
6
 
3
7
  module Pastel
4
8
  # Responsible for parsing color symbols out of text with color escapes
@@ -9,15 +13,16 @@ module Pastel
9
13
  class ColorParser
10
14
  include ANSI
11
15
 
12
- ESC = "\x1b".freeze
13
- CSI = "\[".freeze
16
+ ESC = "\x1b"
17
+ CSI = "\["
14
18
 
15
19
  # Parse color escape sequences into a list of hashes
16
20
  # corresponding to the color attributes being set by these
17
21
  # sequences
18
22
  #
19
23
  # @example
20
- # parse("\e[32mfoo\e[0m") # => [{colors: [:green], text: 'foo'}
24
+ # parse("\e[32mfoo\e[0m")
25
+ # # => [{foreground: :green, text: "foo"}
21
26
  #
22
27
  # @param [String] text
23
28
  # the text to parse for presence of color ansi codes
@@ -30,20 +35,19 @@ module Pastel
30
35
  state = {}
31
36
  result = []
32
37
  ansi_stack = []
33
- text_chunk = ''
38
+ text_chunk = []
34
39
 
35
40
  until scanner.eos?
36
41
  char = scanner.getch
37
42
  # match control
38
43
  if char == ESC && (delim = scanner.getch) == CSI
39
- if scanner.scan(/^0m/)
44
+ if scanner.scan(/^0?m/) # reset
40
45
  unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
41
46
  ansi_stack = []
42
47
  elsif scanner.scan(/^([1-9;:]+)m/)
43
48
  # ansi codes separated by text
44
49
  if !text_chunk.empty? && !ansi_stack.empty?
45
50
  unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
46
- ansi_stack = []
47
51
  end
48
52
  scanner[1].split(/:|;/).each do |code|
49
53
  ansi_stack << code
@@ -51,10 +55,10 @@ module Pastel
51
55
  end
52
56
 
53
57
  if !text_chunk.empty?
54
- state[:text] = text_chunk
58
+ state[:text] = text_chunk.join
55
59
  result.push(state)
56
60
  state = {}
57
- text_chunk = ''
61
+ text_chunk.clear
58
62
  end
59
63
  elsif char == ESC # broken escape
60
64
  text_chunk << char + delim.to_s
@@ -64,12 +68,12 @@ module Pastel
64
68
  end
65
69
 
66
70
  if !text_chunk.empty?
67
- state[:text] = text_chunk
71
+ state[:text] = text_chunk.join
68
72
  end
69
73
  if !ansi_stack.empty?
70
74
  unpack_ansi(ansi_stack) { |attr, name| state[attr] = name}
71
75
  end
72
- if state.values.any? { |val| !val.empty? }
76
+ if !state[:text].to_s.empty?
73
77
  result.push(state)
74
78
  end
75
79
  result
@@ -84,10 +88,8 @@ module Pastel
84
88
  #
85
89
  # @api private
86
90
  def self.unpack_ansi(ansi_stack)
87
- ansi_stack.each do |ansi|
88
- name = ansi_for(ansi)
89
- attr = attribute_for(ansi)
90
- yield attr, name
91
+ ansi_stack.each do |code|
92
+ yield(attribute_name(code), color_name(code))
91
93
  end
92
94
  end
93
95
 
@@ -99,7 +101,7 @@ module Pastel
99
101
  # @return [Symbol]
100
102
  #
101
103
  # @api private
102
- def self.attribute_for(ansi)
104
+ def self.attribute_name(ansi)
103
105
  if ANSI.foreground?(ansi)
104
106
  :foreground
105
107
  elsif ANSI.background?(ansi)
@@ -109,9 +111,13 @@ module Pastel
109
111
  end
110
112
  end
111
113
 
114
+ # Convert ANSI code to color name
115
+ #
116
+ # @return [String]
117
+ #
112
118
  # @api private
113
- def self.ansi_for(ansi)
114
- ATTRIBUTES.key(ansi.to_i)
119
+ def self.color_name(ansi_code)
120
+ ATTRIBUTES.key(ansi_code.to_i)
115
121
  end
116
122
  end # Parser
117
123
  end # Pastel
@@ -1,4 +1,6 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "detached"
2
4
 
3
5
  module Pastel
4
6
  # Contains logic for resolving styles applied to component
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Pastel
4
4
  # Collects a list of decorators for styling a string
@@ -6,14 +6,27 @@ module Pastel
6
6
  # @api private
7
7
  class DecoratorChain
8
8
  include Enumerable
9
- include Equatable
10
9
 
11
- 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)
12
23
  @decorators = decorators
13
24
  end
14
25
 
15
26
  # Add decorator
16
27
  #
28
+ # @param [String] decorator
29
+ #
17
30
  # @api public
18
31
  def add(decorator)
19
32
  if decorators.include?(decorator)
@@ -30,13 +43,40 @@ module Pastel
30
43
  decorators.each(&block)
31
44
  end
32
45
 
33
- # Create an empty decorator chain
46
+ # Compare colors for equality of attributes
34
47
  #
35
- # @return [DecoratorChain]
48
+ # @return [Boolean]
36
49
  #
37
50
  # @api public
38
- def self.empty
39
- 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
40
80
  end
41
81
 
42
82
  protected
@@ -1,4 +1,9 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ require_relative "color_parser"
6
+ require_relative "decorator_chain"
2
7
 
3
8
  module Pastel
4
9
  # Wrapes the {DecoratorChain} to allow for easy resolution
@@ -7,13 +12,19 @@ module Pastel
7
12
  # @api private
8
13
  class Delegator
9
14
  extend Forwardable
10
- include Equatable
11
15
 
12
- def_delegators '@resolver.color', :valid?, :styles, :strip, :decorate,
16
+ def_delegators "@resolver.color", :valid?, :styles, :strip, :decorate,
13
17
  :enabled?, :colored?, :alias_color, :lookup
14
18
 
15
19
  def_delegators ColorParser, :parse
16
- 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
17
28
 
18
29
  # Create Delegator
19
30
  #
@@ -21,20 +32,31 @@ module Pastel
21
32
  #
22
33
  # @param [ColorResolver] resolver
23
34
  #
24
- # @param [DecoratorChain] base
35
+ # @param [DecoratorChain] chain
25
36
  #
26
37
  # @api private
27
- def initialize(resolver, base)
38
+ def initialize(resolver, chain)
28
39
  @resolver = resolver
29
- @base = base
40
+ @chain = chain
30
41
  end
31
42
 
43
+ # Compare delegated objects for equality of attributes
44
+ #
45
+ # @return [Boolean]
46
+ #
32
47
  # @api public
33
- def self.for(resolver, base)
34
- new(resolver, base)
48
+ def eql?(other)
49
+ instance_of?(other.class) && chain.eql?(other.chain)
35
50
  end
36
51
 
37
- 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
38
60
 
39
61
  # Object string representation
40
62
  #
@@ -42,44 +64,53 @@ module Pastel
42
64
  #
43
65
  # @api
44
66
  def inspect
45
- "#<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
46
78
  end
47
- alias_method :to_s, :inspect
48
79
 
49
80
  protected
50
81
 
51
- attr_reader :base
82
+ attr_reader :chain
52
83
 
53
84
  attr_reader :resolver
54
85
 
55
- # Wrap colors
86
+ # Handles color method calls
56
87
  #
57
88
  # @api private
58
- def wrap(base)
59
- self.class.new(resolver, base)
60
- end
61
-
62
89
  def method_missing(method_name, *args, &block)
63
- new_base = base.add(method_name)
64
- delegator = wrap(new_base)
65
- 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
66
93
  delegator
67
94
  else
68
- string = args.join
69
- string << evaluate_block(&block) if block_given?
70
- resolver.resolve(new_base, string)
95
+ strings = args.dup
96
+ strings << evaluate_block(&block) if block_given?
97
+ resolver.resolve(new_chain, strings.join)
71
98
  end
72
99
  end
73
100
 
101
+ # Check if color is valid
102
+ #
103
+ # @api private
74
104
  def respond_to_missing?(name, include_all = false)
75
- resolver.color.respond_to?(name, include_all) || valid?(name) || super
105
+ resolver.color.respond_to?(name, include_all) ||
106
+ resolver.color.valid?(name) || super
76
107
  end
77
108
 
78
109
  # Evaluate color block
79
110
  #
80
111
  # @api private
81
112
  def evaluate_block(&block)
82
- delegator = self.class.new(resolver, DecoratorChain.empty)
113
+ delegator = self.class.wrap(resolver)
83
114
  delegator.instance_eval(&block)
84
115
  end
85
116
  end # Delegator
@@ -1,10 +1,8 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Pastel
4
4
  # A class representing detached color
5
5
  class Detached
6
- include Equatable
7
-
8
6
  # Initialize a detached object
9
7
  #
10
8
  # @param [Pastel::Color] color
@@ -22,6 +20,8 @@ module Pastel
22
20
  # Decorate the values corresponding to styles
23
21
  #
24
22
  # @example
23
+ # Detached(Color.new, :red, :bold).call("hello")
24
+ # # => "\e[31mhello\e[0m"
25
25
  #
26
26
  # @param [String] value
27
27
  # the stirng to decorate with styles
@@ -33,14 +33,50 @@ module Pastel
33
33
  value = args.join
34
34
  @color.decorate(value, *styles)
35
35
  end
36
- alias_method :[], :call
36
+ alias [] call
37
37
 
38
38
  # @api public
39
39
  def to_proc
40
40
  self
41
41
  end
42
42
 
43
- 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
44
80
 
45
81
  # @api private
46
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.0'
4
+ VERSION = "0.8.0"
5
5
  end
metadata CHANGED
@@ -1,98 +1,70 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pastel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-27 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.5.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 0.5.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: tty-color
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: 0.4.0
19
+ version: '0.5'
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
- version: 0.4.0
26
+ version: '0.5'
41
27
  - !ruby/object:Gem::Dependency
42
- name: bundler
28
+ name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
46
32
  - !ruby/object:Gem::Version
47
- version: 1.5.0
48
- - - "<"
49
- - !ruby/object:Gem::Version
50
- version: '2.0'
33
+ version: '0'
51
34
  type: :development
52
35
  prerelease: false
53
36
  version_requirements: !ruby/object:Gem::Requirement
54
37
  requirements:
55
38
  - - ">="
56
39
  - !ruby/object:Gem::Version
57
- version: 1.5.0
58
- - - "<"
59
- - !ruby/object:Gem::Version
60
- version: '2.0'
40
+ version: '0'
61
41
  - !ruby/object:Gem::Dependency
62
- name: rake
42
+ name: rspec
63
43
  requirement: !ruby/object:Gem::Requirement
64
44
  requirements:
65
45
  - - ">="
66
46
  - !ruby/object:Gem::Version
67
- version: '0'
47
+ version: '3.0'
68
48
  type: :development
69
49
  prerelease: false
70
50
  version_requirements: !ruby/object:Gem::Requirement
71
51
  requirements:
72
52
  - - ">="
73
53
  - !ruby/object:Gem::Version
74
- version: '0'
54
+ version: '3.0'
75
55
  description: Terminal strings styling with intuitive and clean API.
76
56
  email:
77
- - ''
57
+ - piotr@piotrmurach.com
78
58
  executables: []
79
59
  extensions: []
80
- extra_rdoc_files: []
60
+ extra_rdoc_files:
61
+ - README.md
62
+ - CHANGELOG.md
63
+ - LICENSE.txt
81
64
  files:
82
- - ".gitignore"
83
- - ".rspec"
84
- - ".travis.yml"
85
65
  - CHANGELOG.md
86
- - Gemfile
87
66
  - LICENSE.txt
88
67
  - README.md
89
- - Rakefile
90
- - appveyor.yml
91
- - assets/pastel_logo.png
92
- - assets/screenshot.png
93
- - benchmarks/nesting_speed.rb
94
- - benchmarks/speed.rb
95
- - examples/palette.rb
96
68
  - lib/pastel.rb
97
69
  - lib/pastel/alias_importer.rb
98
70
  - lib/pastel/ansi.rb
@@ -103,35 +75,16 @@ files:
103
75
  - lib/pastel/delegator.rb
104
76
  - lib/pastel/detached.rb
105
77
  - lib/pastel/version.rb
106
- - pastel.gemspec
107
- - spec/spec_helper.rb
108
- - spec/unit/alias_color_spec.rb
109
- - spec/unit/alias_importer_spec.rb
110
- - spec/unit/color/alias_color_spec.rb
111
- - spec/unit/color/code_spec.rb
112
- - spec/unit/color/colored_spec.rb
113
- - spec/unit/color/decorate_spec.rb
114
- - spec/unit/color/equal_spec.rb
115
- - spec/unit/color/lookup_spec.rb
116
- - spec/unit/color/new_spec.rb
117
- - spec/unit/color/strip_spec.rb
118
- - spec/unit/color/styles_spec.rb
119
- - spec/unit/color/valid_spec.rb
120
- - spec/unit/color_parser_spec.rb
121
- - spec/unit/decorate_dsl_spec.rb
122
- - spec/unit/decorator_chain_spec.rb
123
- - spec/unit/delegator_spec.rb
124
- - spec/unit/detach_spec.rb
125
- - spec/unit/new_spec.rb
126
- - spec/unit/respond_to_spec.rb
127
- - spec/unit/undecorate_spec.rb
128
- - tasks/console.rake
129
- - tasks/coverage.rake
130
- - tasks/spec.rake
131
- homepage: https://github.com/piotrmurach/pastel
78
+ homepage: https://ttytoolkit.org
132
79
  licenses:
133
80
  - MIT
134
- metadata: {}
81
+ metadata:
82
+ allowed_push_host: https://rubygems.org
83
+ bug_tracker_uri: https://github.com/piotrmurach/pastel/issues
84
+ changelog_uri: https://github.com/piotrmurach/pastel/blob/master/CHANGELOG.md
85
+ documentation_uri: https://www.rubydoc.info/gems/pastel
86
+ homepage_uri: https://ttytoolkit.org
87
+ source_code_uri: https://github.com/piotrmurach/pastel
135
88
  post_install_message:
136
89
  rdoc_options: []
137
90
  require_paths:
@@ -140,38 +93,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
93
  requirements:
141
94
  - - ">="
142
95
  - !ruby/object:Gem::Version
143
- version: '0'
96
+ version: 2.0.0
144
97
  required_rubygems_version: !ruby/object:Gem::Requirement
145
98
  requirements:
146
99
  - - ">="
147
100
  - !ruby/object:Gem::Version
148
101
  version: '0'
149
102
  requirements: []
150
- rubyforge_project:
151
- rubygems_version: 2.5.1
103
+ rubygems_version: 3.1.2
152
104
  signing_key:
153
105
  specification_version: 4
154
106
  summary: Terminal strings styling with intuitive and clean API.
155
- test_files:
156
- - spec/spec_helper.rb
157
- - spec/unit/alias_color_spec.rb
158
- - spec/unit/alias_importer_spec.rb
159
- - spec/unit/color/alias_color_spec.rb
160
- - spec/unit/color/code_spec.rb
161
- - spec/unit/color/colored_spec.rb
162
- - spec/unit/color/decorate_spec.rb
163
- - spec/unit/color/equal_spec.rb
164
- - spec/unit/color/lookup_spec.rb
165
- - spec/unit/color/new_spec.rb
166
- - spec/unit/color/strip_spec.rb
167
- - spec/unit/color/styles_spec.rb
168
- - spec/unit/color/valid_spec.rb
169
- - spec/unit/color_parser_spec.rb
170
- - spec/unit/decorate_dsl_spec.rb
171
- - spec/unit/decorator_chain_spec.rb
172
- - spec/unit/delegator_spec.rb
173
- - spec/unit/detach_spec.rb
174
- - spec/unit/new_spec.rb
175
- - spec/unit/respond_to_spec.rb
176
- - spec/unit/undecorate_spec.rb
177
- has_rdoc:
107
+ test_files: []