paintbrush 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +17 -1
- data/Rakefile +1 -0
- data/lib/paintbrush/bounded_color_element.rb +49 -0
- data/lib/paintbrush/color_element.rb +27 -0
- data/lib/paintbrush/colorized_string.rb +29 -13
- data/lib/paintbrush/colors.rb +5 -9
- data/lib/paintbrush/configuration.rb +40 -0
- data/lib/paintbrush/element_tree.rb +46 -0
- data/lib/paintbrush/escapes.rb +15 -0
- data/lib/paintbrush/version.rb +1 -1
- data/lib/paintbrush.rb +10 -3
- data/rspec-documentation/pages/Introduction.md +36 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 178fc999ac3d70a2f9dc640d1c3a187aac191019a1762af80f922144ab18aeb5
|
4
|
+
data.tar.gz: e1f996291bc1748c19ee6389415c896e14f98665b4297cc2217e20fc1657603e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a05f14e7eb6ce19b86e8301e01000f51651ea01d93470a9a80928e3060e473800434141e537e71343995676c1131dbf69a4c6ecc271f9a2b37f52124fda5cf7
|
7
|
+
data.tar.gz: 4f4a5c99d916f055706e366fb7e56bec5a29223d04c604eb04686bcfa6cb596a78a6fdfd685b2a8df3804cf23bb60ce358d9b078d1426fd164b9c5e638d7b954
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
paintbrush (0.1.
|
4
|
+
paintbrush (0.1.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -10,23 +10,38 @@ GEM
|
|
10
10
|
concurrent-ruby (1.2.2)
|
11
11
|
devpack (0.4.1)
|
12
12
|
diff-lcs (1.5.0)
|
13
|
+
htmlbeautifier (1.4.2)
|
13
14
|
i18n (1.13.0)
|
14
15
|
concurrent-ruby (~> 1.0)
|
15
16
|
json (2.6.3)
|
17
|
+
kramdown (2.4.0)
|
18
|
+
rexml
|
19
|
+
kramdown-parser-gfm (1.1.0)
|
20
|
+
kramdown (~> 2.0)
|
16
21
|
paint (2.3.0)
|
17
22
|
parallel (1.23.0)
|
18
23
|
parser (3.2.2.1)
|
19
24
|
ast (~> 2.4.1)
|
20
25
|
rainbow (3.1.1)
|
21
26
|
rake (13.0.6)
|
27
|
+
redcarpet (3.6.0)
|
22
28
|
regexp_parser (2.8.0)
|
23
29
|
rexml (3.2.5)
|
30
|
+
rouge (4.1.1)
|
24
31
|
rspec (3.12.0)
|
25
32
|
rspec-core (~> 3.12.0)
|
26
33
|
rspec-expectations (~> 3.12.0)
|
27
34
|
rspec-mocks (~> 3.12.0)
|
28
35
|
rspec-core (3.12.2)
|
29
36
|
rspec-support (~> 3.12.0)
|
37
|
+
rspec-documentation (0.0.2)
|
38
|
+
htmlbeautifier (~> 1.4)
|
39
|
+
kramdown (~> 2.4)
|
40
|
+
kramdown-parser-gfm (~> 1.1)
|
41
|
+
paintbrush (~> 0.1.1)
|
42
|
+
redcarpet (~> 3.6)
|
43
|
+
rouge (~> 4.1)
|
44
|
+
rspec (~> 3.12)
|
30
45
|
rspec-expectations (3.12.3)
|
31
46
|
diff-lcs (>= 1.2.0, < 2.0)
|
32
47
|
rspec-support (~> 3.12.0)
|
@@ -70,6 +85,7 @@ DEPENDENCIES
|
|
70
85
|
paintbrush!
|
71
86
|
rake (~> 13.0)
|
72
87
|
rspec (~> 3.0)
|
88
|
+
rspec-documentation (~> 0.0.2)
|
73
89
|
rubocop (~> 1.51)
|
74
90
|
rubocop-rake (~> 0.6.0)
|
75
91
|
rubocop-rspec (~> 2.22)
|
data/Rakefile
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paintbrush
|
4
|
+
# Wraps a Paintbrush::ColorElement instance and maps its start and end boundaries within a
|
5
|
+
# compiled escaped string by matching specific unique (indexed) escape codes. Provides
|
6
|
+
# `#surround?` for detecting if another element exists within the current element's boundaries.
|
7
|
+
class BoundedColorElement
|
8
|
+
def initialize(color_element:, escaped_output:)
|
9
|
+
@color_element = color_element
|
10
|
+
@escaped_output = escaped_output
|
11
|
+
end
|
12
|
+
|
13
|
+
def surround?(element)
|
14
|
+
return false if element == self
|
15
|
+
return false unless element.open_index.between?(open_index, close_index)
|
16
|
+
return false unless element.close_index.between?(open_index, close_index)
|
17
|
+
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect
|
22
|
+
"<#{self.class} boundaries=#{boundaries}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
def index
|
26
|
+
color_element.index
|
27
|
+
end
|
28
|
+
|
29
|
+
def code
|
30
|
+
color_element.code
|
31
|
+
end
|
32
|
+
|
33
|
+
def boundaries
|
34
|
+
@boundaries ||= [open_index, close_index]
|
35
|
+
end
|
36
|
+
|
37
|
+
def open_index
|
38
|
+
@open_index ||= escaped_output.index(Escapes.open(index))
|
39
|
+
end
|
40
|
+
|
41
|
+
def close_index
|
42
|
+
escaped_output.index(Escapes.close(index))
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :escaped_output, :color_element
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paintbrush
|
4
|
+
# Provides a substring enclosed in unique escape codes for later colorization when the full
|
5
|
+
# string has been created and all interpolation is completed. Adds itself to a provided stack
|
6
|
+
# of ColorElement objects on initialization.
|
7
|
+
class ColorElement
|
8
|
+
attr_reader :stack, :code, :string, :index
|
9
|
+
attr_accessor :open_index, :close_index
|
10
|
+
|
11
|
+
def initialize(stack:, code:, string:)
|
12
|
+
@stack = stack
|
13
|
+
@code = code
|
14
|
+
@string = string
|
15
|
+
@index = stack.size
|
16
|
+
stack << self
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{Escapes.open(index)}#{string}#{Escapes.close(index)}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"<#{self.class.name} index=#{index} code=#{code}>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -5,44 +5,60 @@ module Paintbrush
|
|
5
5
|
# sequences to store references to start and end of each coloring method to allow nested
|
6
6
|
# colorizing with string interpolation within each individual call to `paintbrush`.
|
7
7
|
class ColorizedString
|
8
|
-
def initialize(&block)
|
8
|
+
def initialize(colorize:, &block)
|
9
|
+
@colorize = colorize
|
9
10
|
@block = block
|
10
|
-
@
|
11
|
+
@stack = []
|
11
12
|
end
|
12
13
|
|
13
14
|
# Returns a colorized string by injecting escape codes into the various calls to each color
|
14
15
|
# method in the provided block, rebuilds the string and returns the value with regular ANSI
|
15
16
|
# color codes ready to be output to a console.
|
16
17
|
def colorized
|
17
|
-
|
18
|
+
Configuration.with_configuration(colorize: @colorize) do
|
19
|
+
colorized_string
|
20
|
+
end
|
18
21
|
end
|
19
22
|
|
20
23
|
private
|
21
24
|
|
22
|
-
attr_reader :block, :
|
25
|
+
attr_reader :block, :stack
|
26
|
+
|
27
|
+
def colorized_string(string: escaped_output, tree: element_tree)
|
28
|
+
tree[:children].reduce(string) do |output, child|
|
29
|
+
subbed = subbed_string(output, child[:node], tree[:node])
|
30
|
+
next subbed if child[:children].empty?
|
23
31
|
|
24
|
-
|
25
|
-
codes.each.with_index.reduce(escaped_output) do |string, (code, index)|
|
26
|
-
restored_color_code = index + 1 == codes.size ? '0' : codes[index + 1]
|
27
|
-
subbed_string(string, index, code, restored_color_code)
|
32
|
+
colorized_string(string: subbed, tree: child)
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
def
|
36
|
+
def bounded_color_elements
|
37
|
+
@bounded_color_elements ||= stack.map do |color_element|
|
38
|
+
BoundedColorElement.new(color_element: color_element, escaped_output: escaped_output)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def element_tree
|
43
|
+
@element_tree ||= ElementTree.new(bounded_color_elements: bounded_color_elements).tree
|
44
|
+
end
|
45
|
+
|
46
|
+
def subbed_string(string, color_element, parent_color_element)
|
47
|
+
restored_color_code = parent_color_element.nil? ? '0' : parent_color_element.code
|
32
48
|
string
|
33
|
-
.sub(
|
34
|
-
.sub(
|
49
|
+
.sub(Escapes.open(color_element.index).to_s, "\e[#{color_element.code}m")
|
50
|
+
.sub(Escapes.close(color_element.index).to_s, "\e[0m\e[#{restored_color_code}m")
|
35
51
|
end
|
36
52
|
|
37
53
|
def escaped_output
|
38
|
-
context.instance_eval(&block)
|
54
|
+
@escaped_output ||= context.instance_eval(&block)
|
39
55
|
end
|
40
56
|
|
41
57
|
def context
|
42
58
|
eval('self', block.binding, __FILE__, __LINE__).dup.tap do |context|
|
43
59
|
context.send(:include, Paintbrush::Colors) if context.respond_to?(:include)
|
44
60
|
context.send(:extend, Paintbrush::Colors) if context.respond_to?(:extend)
|
45
|
-
context.send(:instance_variable_set, :@
|
61
|
+
context.send(:instance_variable_set, :@__stack, stack)
|
46
62
|
end
|
47
63
|
end
|
48
64
|
end
|
data/lib/paintbrush/colors.rb
CHANGED
@@ -6,11 +6,6 @@ module Paintbrush
|
|
6
6
|
# string to be reconstituted afterwards with nested strings restoring the previous color once
|
7
7
|
# they have terminated.
|
8
8
|
module Colors
|
9
|
-
ESCAPE_START_OPEN = "\e[3;15;17]OPEN:"
|
10
|
-
ESCAPE_START_CLOSE = "\e[3;15;17]CLOSE:"
|
11
|
-
ESCAPE_END_OPEN = "\e[17;15;3]OPEN:"
|
12
|
-
ESCAPE_END_CLOSE = "\e[17;15;3]CLOSE:"
|
13
|
-
|
14
9
|
COLOR_CODES = {
|
15
10
|
black: '30',
|
16
11
|
red: '31',
|
@@ -25,10 +20,11 @@ module Paintbrush
|
|
25
20
|
|
26
21
|
COLOR_CODES.each do |name, code|
|
27
22
|
define_method name do |string|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
if Configuration.colorize?
|
24
|
+
ColorElement.new(stack: @__stack, code: code, string: string).to_s
|
25
|
+
else
|
26
|
+
string
|
27
|
+
end
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paintbrush
|
4
|
+
# Provides a configuration interface for Paintbrush features, allows disabling colorization.
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# ```ruby
|
9
|
+
# Paintbrush::Configuration.colorize = false
|
10
|
+
# ```
|
11
|
+
module Configuration
|
12
|
+
@defaults = {
|
13
|
+
colorize: true
|
14
|
+
}
|
15
|
+
|
16
|
+
@configuration = {}
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_reader :configuration, :defaults
|
20
|
+
|
21
|
+
def colorize=(val)
|
22
|
+
configuration[:colorize] = val
|
23
|
+
end
|
24
|
+
|
25
|
+
def colorize?
|
26
|
+
configuration.fetch(:colorize, defaults[:colorize])
|
27
|
+
end
|
28
|
+
|
29
|
+
def reset
|
30
|
+
@configuration = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def with_configuration(**options, &block)
|
34
|
+
previous = configuration.dup
|
35
|
+
options.compact.each { |key, value| configuration[key] = value unless configuration.key?(key) }
|
36
|
+
block.call.tap { @configuration = previous }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paintbrush
|
4
|
+
# A tree of BoundedColorElement objects. Used to build a full tree of colorized substrings in
|
5
|
+
# order to allow discovery of parent substrings and use their color code to restore to when the
|
6
|
+
# substring is terminated. Allows deeply-nested colorized strings.
|
7
|
+
class ElementTree
|
8
|
+
attr_reader :tree
|
9
|
+
|
10
|
+
def initialize(bounded_color_elements:)
|
11
|
+
@bounded_color_elements = bounded_color_elements
|
12
|
+
@tree = { node: nil, children: [] }
|
13
|
+
build_tree(boundary_end: bounded_color_elements.map(&:close_index).max)
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_tree(boundary_end:, root: @tree, elements: bounded_color_elements, boundary_start: 0)
|
17
|
+
root_nodes, non_root_nodes = partitioned_elements(elements, boundary_start, boundary_end)
|
18
|
+
|
19
|
+
root_nodes.each do |node|
|
20
|
+
root[:children] << child_node(node)
|
21
|
+
build_tree(
|
22
|
+
root: root[:children].last,
|
23
|
+
elements: non_root_nodes,
|
24
|
+
boundary_start: node.open_index,
|
25
|
+
boundary_end: node.close_index
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :bounded_color_elements
|
33
|
+
|
34
|
+
def child_node(node)
|
35
|
+
{ node: node, children: [] }
|
36
|
+
end
|
37
|
+
|
38
|
+
def partitioned_elements(elements, boundary_start, boundary_end)
|
39
|
+
elements.partition do |element|
|
40
|
+
next false if elements.any? { |child| child.surround?(element) }
|
41
|
+
|
42
|
+
element.boundaries.all? { |index| index.between?(boundary_start, boundary_end) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paintbrush
|
4
|
+
# Provides an authority on escape code generation. Provides `.close` and `.open`, both of which
|
5
|
+
# receive an index (i.e. the current size of the stack). Used for escape code insertion and comparison.
|
6
|
+
module Escapes
|
7
|
+
def self.open(index)
|
8
|
+
"\e[3;15;17]START_OPEN:#{index}:\e[3;15;17]START_CLOSE"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.close(index)
|
12
|
+
"\e[17;15;3]END_OPEN:#{index}:\e[17;15;3]END_CLOSE"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/paintbrush/version.rb
CHANGED
data/lib/paintbrush.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'paintbrush/version'
|
4
|
+
require_relative 'paintbrush/configuration'
|
5
|
+
require_relative 'paintbrush/escapes'
|
4
6
|
require_relative 'paintbrush/colors'
|
5
7
|
require_relative 'paintbrush/colorized_string'
|
8
|
+
require_relative 'paintbrush/color_element'
|
9
|
+
require_relative 'paintbrush/bounded_color_element'
|
10
|
+
require_relative 'paintbrush/element_tree'
|
6
11
|
|
7
12
|
# Colorizes a string, provides `#paintbrush`. When included/extended in a class, call
|
8
13
|
# `#paintbrush` and pass a block to use the provided dynamically defined methods, e.g.:
|
@@ -16,9 +21,11 @@ require_relative 'paintbrush/colorized_string'
|
|
16
21
|
# end
|
17
22
|
# ```
|
18
23
|
module Paintbrush
|
19
|
-
|
24
|
+
def self.paintbrush(colorize: nil, &block)
|
25
|
+
ColorizedString.new(colorize: colorize, &block).colorized
|
26
|
+
end
|
20
27
|
|
21
|
-
def paintbrush(&block)
|
22
|
-
|
28
|
+
def paintbrush(colorize: nil, &block)
|
29
|
+
Paintbrush.paintbrush(colorize: colorize, &block)
|
23
30
|
end
|
24
31
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Paintbrush
|
2
|
+
|
3
|
+
Simple and concise string colorization for _Ruby_ without overloading `String` methods or requiring verbose class/method invocation.
|
4
|
+
|
5
|
+
_Paintbrush_ has zero dependencies and does not pollute any namespaces or objects outside of the `#paintbrush` method wherever you include the `Paintbrush` module.
|
6
|
+
|
7
|
+
Nesting is supported, allowing you to use multiple colors within the same string. The previous color is automatically restored.
|
8
|
+
|
9
|
+
```rspec:ansi
|
10
|
+
require 'paintbrush'
|
11
|
+
|
12
|
+
extend Paintbrush
|
13
|
+
|
14
|
+
output = paintbrush { purple "You used #{green 'four'} #{blue "(#{cyan '4'})"} #{yellow 'colors'} today!" }
|
15
|
+
it_documents output do
|
16
|
+
expect(output).to eql "\e[35mYou used \e[32mfour\e[0m\e[35m " \
|
17
|
+
"\e[34m(\e[36m4\e[0m\e[34m)\e[0m\e[35m " \
|
18
|
+
"\e[33mcolors\e[0m\e[35m today!\e[0m\e[0m"
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
```rspec:ansi
|
23
|
+
require 'paintbrush'
|
24
|
+
|
25
|
+
extend Paintbrush
|
26
|
+
|
27
|
+
output = paintbrush do
|
28
|
+
"#{blue 'foo'} #{green "bar #{cyan %w[foo bar baz].join(', ')} with #{cyan 'qux'} and quux"} and corge"
|
29
|
+
end
|
30
|
+
|
31
|
+
it_documents output do
|
32
|
+
expect(output).to eql "\e[34mfoo\e[0m\e[0m \e[32mbar \e[36mfoo, bar, baz" \
|
33
|
+
"\e[0m\e[32m with \e[36mqux\e[0m\e[32m "\
|
34
|
+
"and quux\e[0m\e[0m and corge"
|
35
|
+
end
|
36
|
+
```
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paintbrush
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Farrell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Provides a set of encapsulated methods for nested colorization of strings.
|
14
14
|
email:
|
@@ -28,10 +28,16 @@ files:
|
|
28
28
|
- Rakefile
|
29
29
|
- doc/example.png
|
30
30
|
- lib/paintbrush.rb
|
31
|
+
- lib/paintbrush/bounded_color_element.rb
|
32
|
+
- lib/paintbrush/color_element.rb
|
31
33
|
- lib/paintbrush/colorized_string.rb
|
32
34
|
- lib/paintbrush/colors.rb
|
35
|
+
- lib/paintbrush/configuration.rb
|
36
|
+
- lib/paintbrush/element_tree.rb
|
37
|
+
- lib/paintbrush/escapes.rb
|
33
38
|
- lib/paintbrush/version.rb
|
34
39
|
- paintbrush.gemspec
|
40
|
+
- rspec-documentation/pages/Introduction.md
|
35
41
|
- sig/paintbrush.rbs
|
36
42
|
homepage: https://github.com/bobf/paintbrush
|
37
43
|
licenses: []
|