pastel 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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: []