paintbrush 0.1.1 → 0.1.3
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/Makefile +9 -0
- data/README.md +3 -0
- data/lib/paintbrush.rb +21 -11
- data/lib/{paintbrush → paintbrush_support}/bounded_color_element.rb +1 -1
- data/lib/{paintbrush → paintbrush_support}/color_element.rb +1 -1
- data/lib/{paintbrush → paintbrush_support}/colorized_string.rb +8 -5
- data/lib/paintbrush_support/colors.rb +60 -0
- data/lib/paintbrush_support/configuration.rb +40 -0
- data/lib/{paintbrush → paintbrush_support}/element_tree.rb +1 -1
- data/lib/{paintbrush → paintbrush_support}/escapes.rb +1 -1
- data/lib/paintbrush_support/hex_color_code.rb +40 -0
- data/lib/paintbrush_support/version.rb +5 -0
- data/paintbrush.gemspec +3 -2
- data/rspec-documentation/pages/000-Introduction.md +23 -0
- data/rspec-documentation/pages/010-Colors.md +52 -0
- data/rspec-documentation/pages/020-Examples/010-Basic Usage.md +19 -0
- data/rspec-documentation/pages/020-Examples/020-Bright Colors.md +15 -0
- data/rspec-documentation/pages/020-Examples/030-Nested Colors.md +13 -0
- data/rspec-documentation/pages/020-Examples/040-RGB Colors.md +29 -0
- data/rspec-documentation/pages/020-Examples/050-Dynamic Usage.md +29 -0
- data/rspec-documentation/pages/020-Examples/060-Without Including.md +15 -0
- data/rspec-documentation/pages/020-Examples.md +20 -0
- data/rspec-documentation/pages/030-Configuration.md +63 -0
- data/rspec-documentation/pages/040-How It Works.md +83 -0
- data/rspec-documentation/spec_helper.rb +8 -0
- metadata +25 -12
- data/lib/paintbrush/colors.rb +0 -27
- data/lib/paintbrush/version.rb +0 -5
- data/rspec-documentation/bundle/introduction.html +0 -312
- data/rspec-documentation/pages/Introduction.md +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69b5f9f4807975898e5e3c9ee9a96b183df59a1e57cd642305710479c43e2482
|
4
|
+
data.tar.gz: d2b507b2d2ce9a562bdba5066b8d5331faa9f8e1c11dbeb7e75320bb46dac26d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 321564b1aaa6befd52e1b2703b6ac3345824188434f3634f333c39577b1b50fc7517a91c3490a0e34b865b63bb5e55e101ce287fb570a5e22a763c22cf2aa92a
|
7
|
+
data.tar.gz: 77e3ab29dd45a4bf28a6b6a1a6e6afdc49414de62b58d801eb5d453167a0d87e359613642ca4b9bcb4345565ae619ba56f0002bdc1c09b46057d669c18a5e003
|
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.3)
|
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/Makefile
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
+
project=paintbrush
|
2
|
+
|
1
3
|
.PHONY: test
|
2
4
|
test:
|
3
5
|
bundle exec rspec
|
4
6
|
bundle exec rubocop
|
5
7
|
bundle exec strong_versions
|
8
|
+
bundle exec rspec-documentation
|
9
|
+
|
10
|
+
.PHONY: publish
|
11
|
+
publish:
|
12
|
+
@RSPEC_DOCUMENTATION_URL_ROOT='/$(project)' bundle exec rspec-documentation
|
13
|
+
@rsync --delete -r rspec-documentation/bundle/ docs01.bob.frl:/mnt/docs/$(project)/
|
14
|
+
@echo 'Published.'
|
data/README.md
CHANGED
@@ -42,11 +42,14 @@ Include the `Paintbrush` module anywhere and call `#paintbrush` to generate a co
|
|
42
42
|
* `#white`
|
43
43
|
* `#default`
|
44
44
|
|
45
|
+
Hex colors are also available as `#hex_ff00ff` and `#hex_f0f`, allowing a much wider range of colors.
|
46
|
+
|
45
47
|
Use [string interpolation](https://docs.ruby-lang.org/en/3.2/syntax/literals_rdoc.html#label-String+Literals) to nest multiple colors:
|
46
48
|
|
47
49
|
```ruby
|
48
50
|
include Paintbrush
|
49
51
|
puts paintbrush { green "some green text, #{yellow "some yellow text"} and some green again" }
|
52
|
+
puts paintbrush { hex_ff00ff "some magenta #{hex_ffff00 "and some yellow"} and magenta again" }
|
50
53
|
```
|
51
54
|
|
52
55
|
## Alternatives
|
data/lib/paintbrush.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
3
|
+
require_relative 'paintbrush_support/version'
|
4
|
+
require_relative 'paintbrush_support/configuration'
|
5
|
+
require_relative 'paintbrush_support/escapes'
|
6
|
+
require_relative 'paintbrush_support/colors'
|
7
|
+
require_relative 'paintbrush_support/colorized_string'
|
8
|
+
require_relative 'paintbrush_support/color_element'
|
9
|
+
require_relative 'paintbrush_support/hex_color_code'
|
10
|
+
require_relative 'paintbrush_support/bounded_color_element'
|
11
|
+
require_relative 'paintbrush_support/element_tree'
|
10
12
|
|
11
13
|
# Colorizes a string, provides `#paintbrush`. When included/extended in a class, call
|
12
14
|
# `#paintbrush` and pass a block to use the provided dynamically defined methods, e.g.:
|
@@ -20,11 +22,19 @@ require_relative 'paintbrush/element_tree'
|
|
20
22
|
# end
|
21
23
|
# ```
|
22
24
|
module Paintbrush
|
23
|
-
def self.paintbrush(&block)
|
24
|
-
ColorizedString.new(&block).colorized
|
25
|
+
def self.paintbrush(colorize: nil, &block)
|
26
|
+
PaintbrushSupport::ColorizedString.new(colorize: colorize, &block).colorized
|
25
27
|
end
|
26
28
|
|
27
|
-
def
|
28
|
-
|
29
|
+
def self.configure
|
30
|
+
yield PaintbrushSupport::Configuration
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.with_configuration(**options, &block)
|
34
|
+
PaintbrushSupport::Configuration.with_configuration(**options, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def paintbrush(colorize: nil, &block)
|
38
|
+
Paintbrush.paintbrush(colorize: colorize, &block)
|
29
39
|
end
|
30
40
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module PaintbrushSupport
|
4
4
|
# Wraps a Paintbrush::ColorElement instance and maps its start and end boundaries within a
|
5
5
|
# compiled escaped string by matching specific unique (indexed) escape codes. Provides
|
6
6
|
# `#surround?` for detecting if another element exists within the current element's boundaries.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module PaintbrushSupport
|
4
4
|
# Provides a substring enclosed in unique escape codes for later colorization when the full
|
5
5
|
# string has been created and all interpolation is completed. Adds itself to a provided stack
|
6
6
|
# of ColorElement objects on initialization.
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module PaintbrushSupport
|
4
4
|
# Core string colorization, provides various methods for colorizing a string, uses escape
|
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
|
@@ -14,7 +15,9 @@ module Paintbrush
|
|
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
|
@@ -53,8 +56,8 @@ module Paintbrush
|
|
53
56
|
|
54
57
|
def context
|
55
58
|
eval('self', block.binding, __FILE__, __LINE__).dup.tap do |context|
|
56
|
-
context.send(:include,
|
57
|
-
context.send(:extend,
|
59
|
+
context.send(:include, PaintbrushSupport::Colors) if context.respond_to?(:include)
|
60
|
+
context.send(:extend, PaintbrushSupport::Colors) if context.respond_to?(:extend)
|
58
61
|
context.send(:instance_variable_set, :@__stack, stack)
|
59
62
|
end
|
60
63
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaintbrushSupport
|
4
|
+
# Provides methods that are temporarily injected into block context. Each method returns an
|
5
|
+
# escaped string including the current stack size with start and end escape codes, allowing the
|
6
|
+
# string to be reconstituted afterwards with nested strings restoring the previous color once
|
7
|
+
# they have terminated.
|
8
|
+
module Colors
|
9
|
+
COLOR_CODES = {
|
10
|
+
black: '30',
|
11
|
+
red: '31',
|
12
|
+
green: '32',
|
13
|
+
yellow: '33',
|
14
|
+
blue: '34',
|
15
|
+
purple: '35',
|
16
|
+
cyan: '36',
|
17
|
+
white: '37',
|
18
|
+
default: '39',
|
19
|
+
black_b: '90',
|
20
|
+
red_b: '91',
|
21
|
+
green_b: '92',
|
22
|
+
yellow_b: '93',
|
23
|
+
blue_b: '94',
|
24
|
+
purple_b: '95',
|
25
|
+
cyan_b: '96',
|
26
|
+
white_b: '97'
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
HEX_CODE_REGEXP = /(?:hex_[a-fA-F0-9]{3}){1,2}/.freeze
|
30
|
+
|
31
|
+
COLOR_CODES.each do |name, code|
|
32
|
+
define_method name do |string|
|
33
|
+
if Configuration.colorize?
|
34
|
+
ColorElement.new(stack: @__stack, code: code, string: string).to_s
|
35
|
+
else
|
36
|
+
string
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(method_name, *args)
|
42
|
+
return super unless method_name.match?(HEX_CODE_REGEXP)
|
43
|
+
return string unless Configuration.colorize?
|
44
|
+
|
45
|
+
return unless Configuration.colorize?
|
46
|
+
|
47
|
+
ColorElement.new(
|
48
|
+
stack: @__stack,
|
49
|
+
code: HexColorCode.new(hex_code: method_name).escape_sequence,
|
50
|
+
string: args.first
|
51
|
+
).to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def respond_to_missing?(*)
|
55
|
+
return super unless method_name.match?(HEX_CODE_REGEXP)
|
56
|
+
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaintbrushSupport
|
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module PaintbrushSupport
|
4
4
|
# A tree of BoundedColorElement objects. Used to build a full tree of colorized substrings in
|
5
5
|
# order to allow discovery of parent substrings and use their color code to restore to when the
|
6
6
|
# substring is terminated. Allows deeply-nested colorized strings.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module PaintbrushSupport
|
4
4
|
# Provides an authority on escape code generation. Provides `.close` and `.open`, both of which
|
5
5
|
# receive an index (i.e. the current size of the stack). Used for escape code insertion and comparison.
|
6
6
|
module Escapes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaintbrushSupport
|
4
|
+
# Translates a string in format `hex_ff00ff` or `hex_f0f` into an RGB escape code sequence.
|
5
|
+
# Allows calling e.g.:
|
6
|
+
#
|
7
|
+
# paintbrush { hex_ff0ff 'hello in magenta' }
|
8
|
+
#
|
9
|
+
class HexColorCode
|
10
|
+
def initialize(hex_code:)
|
11
|
+
@hex_code = hex_code
|
12
|
+
end
|
13
|
+
|
14
|
+
def escape_sequence
|
15
|
+
(%w[38 2] + encoded_pairs).join(';')
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :hex_code
|
21
|
+
|
22
|
+
def encoded_pairs
|
23
|
+
pairs.map { |pair| pair.to_i(16).to_s }
|
24
|
+
end
|
25
|
+
|
26
|
+
def pairs
|
27
|
+
normalized_hex_string.chars.each_slice(2).map(&:join)
|
28
|
+
end
|
29
|
+
|
30
|
+
def hex_string
|
31
|
+
@hex_string ||= hex_code.to_s.partition('hex_').last
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalized_hex_string
|
35
|
+
return hex_string if hex_string.size == 6
|
36
|
+
|
37
|
+
hex_string.chars.map { |char| "#{char}#{char}" }.join
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/paintbrush.gemspec
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'lib/
|
3
|
+
require_relative 'lib/paintbrush_support/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'paintbrush'
|
7
|
-
spec.version =
|
7
|
+
spec.version = PaintbrushSupport::VERSION
|
8
8
|
spec.authors = ['Bob Farrell']
|
9
9
|
spec.email = ['git@bob.frl']
|
10
|
+
spec.licenses = ['MIT']
|
10
11
|
|
11
12
|
spec.summary = 'Hassle-free text coloring for console applications.'
|
12
13
|
spec.description = 'Provides a set of encapsulated methods for nested colorization of strings.'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Introduction
|
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
|
+
## Quick Example
|
10
|
+
|
11
|
+
```rspec:ansi
|
12
|
+
require 'paintbrush'
|
13
|
+
|
14
|
+
include Paintbrush
|
15
|
+
|
16
|
+
subject { paintbrush { purple "You used #{green 'four'} #{blue "(#{cyan '4'})"} #{yellow 'colors'} today!" } }
|
17
|
+
|
18
|
+
it 'outputs simple colorized strings' do
|
19
|
+
expect(subject).to eql "\e[35mYou used \e[32mfour\e[0m\e[35m " \
|
20
|
+
"\e[34m(\e[36m4\e[0m\e[34m)\e[0m\e[35m " \
|
21
|
+
"\e[33mcolors\e[0m\e[35m today!\e[0m\e[0m"
|
22
|
+
end
|
23
|
+
```
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Colors
|
2
|
+
|
3
|
+
_Paintbrush_ defines the following colors. Each color is avaiable as a method call inside a block passed to the `paintbrush` method.
|
4
|
+
|
5
|
+
## Basic Colors
|
6
|
+
|
7
|
+
* `black`
|
8
|
+
* `red`
|
9
|
+
* `green`
|
10
|
+
* `yellow`
|
11
|
+
* `blue`
|
12
|
+
* `purple`
|
13
|
+
* `cyan`
|
14
|
+
* `white`
|
15
|
+
* `default`
|
16
|
+
|
17
|
+
```rspec:ansi
|
18
|
+
subject { paintbrush { purple 'a purple string' } }
|
19
|
+
|
20
|
+
it { is_expected.to include "\e[35ma purple string" }
|
21
|
+
```
|
22
|
+
|
23
|
+
## Bright Colors
|
24
|
+
|
25
|
+
Add the `_b` suffix to get the "bright" version of the relevant color.
|
26
|
+
|
27
|
+
* `black_b`
|
28
|
+
* `red_b`
|
29
|
+
* `green_b`
|
30
|
+
* `yellow_b`
|
31
|
+
* `blue_b`
|
32
|
+
* `purple_b`
|
33
|
+
* `cyan_b`
|
34
|
+
* `white_b`
|
35
|
+
|
36
|
+
```rspec:ansi
|
37
|
+
subject { paintbrush { purple_b 'a bright purple string' } }
|
38
|
+
|
39
|
+
it { is_expected.to include "\e[95ma bright purple string" }
|
40
|
+
```
|
41
|
+
|
42
|
+
## RGB Colors
|
43
|
+
|
44
|
+
As well as the colors listed below, any RGB hex color code (e.g. `ff00ff`) is available as a method prefixed with `hex_`, e.g. use `hex_ff00ff` for magenta.
|
45
|
+
|
46
|
+
The shorthand versions `#hex_f0f` are also provided, i.e. `#hex_f0f` is equivalent to `#hex_ff00ff`.
|
47
|
+
|
48
|
+
```rspec:ansi
|
49
|
+
subject { paintbrush { hex_f0f 'a magenta string' } }
|
50
|
+
|
51
|
+
it { is_expected.to include "\e[38;2;255;0;255ma magenta string" }
|
52
|
+
```
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Basic Usage
|
2
|
+
|
3
|
+
The most basic usage of _Paintbrush_ is with no colorization at all:
|
4
|
+
|
5
|
+
```rspec:ansi
|
6
|
+
subject { paintbrush { 'an uncolorized string' } }
|
7
|
+
|
8
|
+
it { is_expected.to eql 'an uncolorized string' }
|
9
|
+
```
|
10
|
+
|
11
|
+
As you can see, a duplicate of the original string is returned intact with no modifications.
|
12
|
+
|
13
|
+
The second-most basic usage of _Paintbrush_ is with a single color:
|
14
|
+
|
15
|
+
```rspec:ansi
|
16
|
+
subject { paintbrush { green 'some green text' } }
|
17
|
+
|
18
|
+
it { is_expected.to include 'some green text' }
|
19
|
+
```
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Bright Colors
|
2
|
+
|
3
|
+
Use the `_b` suffix for a color name to make a **bright** color. See [Colors](../colors.html) for more details.
|
4
|
+
|
5
|
+
```rspec:ansi
|
6
|
+
subject { paintbrush { blue_b "bright blue" } }
|
7
|
+
|
8
|
+
it { is_expected.to include 'bright blue' }
|
9
|
+
```
|
10
|
+
|
11
|
+
```rspec:ansi
|
12
|
+
subject { paintbrush { "#{blue "some blue text"} #{blue_b "and some bright blue text"}" } }
|
13
|
+
|
14
|
+
it { is_expected.to include 'bright blue' }
|
15
|
+
```
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Nested Colors
|
2
|
+
|
3
|
+
_Paintbrush_ supports unlimited levels of nesting, allowing you to use one color inside another color and have the text revert back to its previous color. This lets you create complex colorized strings without having to manually revert back manually.
|
4
|
+
|
5
|
+
```rspec:ansi
|
6
|
+
subject do
|
7
|
+
paintbrush do
|
8
|
+
green "green, #{blue "blue, #{cyan "cyan #{yellow "and yellow"}, back to cyan"}, back to blue"}, and back to green"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it { is_expected.to include "and yellow" }
|
13
|
+
```
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# RGB Colors
|
2
|
+
|
3
|
+
Using _RGB_ colors gives you the full range of over 16 Million colors to use in your terminal. We won't provide an example for each color but here are a few to give you an idea of how it works.
|
4
|
+
|
5
|
+
```rspec:ansi
|
6
|
+
subject do
|
7
|
+
paintbrush do
|
8
|
+
"#{hex_f00 'R'}#{hex_ffa500 'A'}#{hex_ff0 'I'}#{hex_080 'N'}" \
|
9
|
+
"#{hex_00f 'B'}#{hex_4b0082 'O'}#{hex_ee82ee 'W'}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'outputs a rainbow' do
|
14
|
+
expect(subject).to eql(
|
15
|
+
"\e[38;2;255;0;0mR\e[0m\e[0m\e[38;2;255;165;0mA\e[0m\e[0m" \
|
16
|
+
"\e[38;2;255;255;0mI\e[0m\e[0m\e[38;2;0;136;0mN\e[0m\e[0m" \
|
17
|
+
"\e[38;2;0;0;255mB\e[0m\e[0m\e[38;2;75;0;130mO\e[0m\e[0m" \
|
18
|
+
"\e[38;2;238;130;238mW\e[0m\e[0m"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
Note that both the full hex code and the abbreviated versions are supported, i.e. `hex_ff0` produces the same output as `hex_ffff00`:
|
24
|
+
|
25
|
+
```rspec:ansi
|
26
|
+
subject { paintbrush { hex_ff0 'yellow' } }
|
27
|
+
|
28
|
+
it { is_expected.to eql(paintbrush { hex_ffff00 'yellow' }) }
|
29
|
+
```
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Dynamic Usage
|
2
|
+
|
3
|
+
You may have situations where the color you wish to use depends on some state that is unknown until your application is running, and may change between each invocation.
|
4
|
+
|
5
|
+
Since _Paintbrush_ colors are regular methods, you can call `public_send` within the block passed to `paintbrush`.
|
6
|
+
|
7
|
+
|
8
|
+
```rspec:ansi
|
9
|
+
subject do
|
10
|
+
paintbrush { blue "The action #{public_send outcome_color, outcome} this time!" }
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:outcome_color) { :green }
|
14
|
+
let(:outcome) { 'succeeded' }
|
15
|
+
|
16
|
+
it { is_expected.to include "\e[32msucceeded\e[0m" }
|
17
|
+
|
18
|
+
```
|
19
|
+
|
20
|
+
```rspec:ansi
|
21
|
+
subject do
|
22
|
+
paintbrush { blue "The action #{public_send outcome_color, outcome} this time!" }
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:outcome_color) { :red }
|
26
|
+
let(:outcome) { 'failed' }
|
27
|
+
|
28
|
+
it { is_expected.to include "\e[31mfailed\e[0m" }
|
29
|
+
```
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Usage Without `include Paintbrush`
|
2
|
+
|
3
|
+
_Paintbrush_ is designed to minimize namespace pollution when used with `include`.
|
4
|
+
|
5
|
+
Only one instance method (`#paintbrush`) is defined on the module, so only one method will be reached by your object's method resolver.
|
6
|
+
|
7
|
+
_Paintbrush_ also uses a separate namespace for its internals, `PaintbrushSupport`, to minimize adding unwanted constants into an instance's namespace when using `include Paintbrush`.
|
8
|
+
|
9
|
+
You may still prefer to not include _Paintbrush_ into your namespace. Simply call `Paintbrush.paintbrush` instead.
|
10
|
+
|
11
|
+
```rspec:ansi
|
12
|
+
subject { Paintbrush.paintbrush { red "I prefer not to #{cyan "include"} Paintbrush" } }
|
13
|
+
|
14
|
+
it { is_expected.to include "I prefer not" }
|
15
|
+
```
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Examples
|
2
|
+
|
3
|
+
See the individual example pages for usage patterns. Examples are provided to cover basic usage as well as more complex nested colors with multiple color variants. Remember to `include Paintbrush` anywhere you wish to use it.
|
4
|
+
|
5
|
+
Experiment with _Paintbrush_ from a terminal to get a feel for it:
|
6
|
+
|
7
|
+
```irb
|
8
|
+
irb(main):001:0> require 'paintbrush'
|
9
|
+
=> true
|
10
|
+
irb(main):002:0> include Paintbrush
|
11
|
+
=> Object
|
12
|
+
irb(main):003:0> puts(paintbrush { green "hello #{cyan 'new'} #{blue 'Paintbrush'} user" })
|
13
|
+
hello new Paintbrush user
|
14
|
+
```
|
15
|
+
|
16
|
+
```rspec:ansi
|
17
|
+
subject { paintbrush { green "hello #{cyan 'new'} #{blue 'Paintbrush'} user" } }
|
18
|
+
|
19
|
+
it { is_expected.to include 'Paintbrush' }
|
20
|
+
```
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Configuration
|
2
|
+
|
3
|
+
_Paintbrush_ provides one simple configuration option, allowing you to enable or disable colorization either globally, per-invocation, or within a block.
|
4
|
+
|
5
|
+
Note that global configuration overrides block configuration, and block configuration overrides per-invocation configuration. i.e. any method-level configurations have no impact if a global configuration is set.
|
6
|
+
|
7
|
+
## Global Configuration
|
8
|
+
|
9
|
+
Disable colorization globally by adding the following code somewhere near the beginning of your application's start-up process (e.g. in _Rails_, an initializer is a good place to put this):
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# config/initializers/paintbrush.rb
|
13
|
+
|
14
|
+
Paintbrush.configure do |config|
|
15
|
+
config.colorize = false if Rails.env.production?
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
All calls to `#paintbrush` will now return a regular, uncolorized string.
|
20
|
+
|
21
|
+
## Block Configuration
|
22
|
+
|
23
|
+
_Paintbrush_ can be configured for the duration of a block by calling `Paintbrush.with_configuration`. e.g. you may want to disable colorization in your tests to make testing output a bit easier. If you're using _RSpec_ you can add the following to `spec/spec_helper.rb`:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# spec/spec_helper.rb
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.around { |example| Paintbrush.with_configuration(colorize: false) { example.call } }
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
```rspec:ansi
|
34
|
+
subject do
|
35
|
+
Paintbrush.with_configuration(colorize: false) { paintbrush { red 'An uncolorized string' } }
|
36
|
+
end
|
37
|
+
|
38
|
+
it { is_expected.to eql 'An uncolorized string' }
|
39
|
+
```
|
40
|
+
|
41
|
+
## Method Invocation Configuration
|
42
|
+
|
43
|
+
Pass `colorize: false` to `paintbrush` directly to disable colorization for a single call. This is especially useful when generating a message in two or more contexts. For example, you may want to render the same message to a development log as well as returning that message in a web response, one with colorization and one without:
|
44
|
+
|
45
|
+
```rspec:ansi
|
46
|
+
def my_message(colorize: true)
|
47
|
+
paintbrush(colorize: colorize) { cyan "A log message with colors in some contexts." }
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { my_message(colorize: true) }
|
51
|
+
|
52
|
+
it { is_expected.to include "\e[36m" }
|
53
|
+
```
|
54
|
+
|
55
|
+
```rspec:ansi
|
56
|
+
def my_message(colorize: true)
|
57
|
+
paintbrush(colorize: colorize) { cyan "A log message with colors in some contexts." }
|
58
|
+
end
|
59
|
+
|
60
|
+
subject { my_message(colorize: false) }
|
61
|
+
|
62
|
+
it { is_expected.not_to include "\e[36m" }
|
63
|
+
```
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# How It Works
|
2
|
+
|
3
|
+
_Paintbrush_ can be broken down into four components:
|
4
|
+
|
5
|
+
1. Context manipulation.
|
6
|
+
1. String encoding.
|
7
|
+
1. Color code tree construction.
|
8
|
+
1. Re-encoding into a colorized string.
|
9
|
+
|
10
|
+
## Context Manipulation
|
11
|
+
|
12
|
+
_Paintbrush_ cares about namespace pollution. It avoids adding methods and constants into a namespace where possible, and it does not overload or extend any other objects. _Paintbrush's_ methods are only available within the block passed to the `#paintbrush` method.
|
13
|
+
|
14
|
+
To achieve this, _Paintbrush_ duplicates the binding of the current block (i.e. the namespace that invoked `#paintbrush`), injects a module `PaintbrushSupport::Colors` (which provides the color methods like `#cyan`) into the duplicated context's `self`, and also adds a `@__stack` instance variable which is unique to each invocation of `#paintbrush`.
|
15
|
+
|
16
|
+
Each call to `#green`, `#blue`, etc. adds a new `PaintbrushSupport::ColorElement` to the stack, which stores the name of the invoked color method, the string it received, and its index in the current stack.
|
17
|
+
|
18
|
+
The `ColorElement` object is then returned so _Ruby_ can interpolate it, calling `ColorElement#to_s` which returns an encoded string.
|
19
|
+
|
20
|
+
## String Encoding
|
21
|
+
|
22
|
+
Each encoded string includes the following:
|
23
|
+
|
24
|
+
* An escape code indicating the beginning of the string.
|
25
|
+
* The index of the item in the current stack.
|
26
|
+
* The original string received to the color method.
|
27
|
+
* An escape code indicating the end of the string.
|
28
|
+
|
29
|
+
The index is encoded to both the start end end boundaries of the substring, which allows nested colorized strings. The structure is similar to open and close tags in _XML_, with each tag having a unique identifier attribute.
|
30
|
+
|
31
|
+
The raw encoded string looks like this (slightly formatted to allow text wrapping):
|
32
|
+
|
33
|
+
```rspec
|
34
|
+
subject do
|
35
|
+
PaintbrushSupport::ColorizedString.new(colorize: true) { red "red #{green "green #{blue "blue"}"}" }
|
36
|
+
.send(:escaped_output)
|
37
|
+
.gsub("CLOSE", "CLOSE ")
|
38
|
+
end
|
39
|
+
|
40
|
+
it { is_expected.to include "green" }
|
41
|
+
```
|
42
|
+
This encoded string could be represented in _XML_, for example:
|
43
|
+
|
44
|
+
```xml
|
45
|
+
<color code="red" id="2">
|
46
|
+
red
|
47
|
+
<color code="green" id="1">
|
48
|
+
green
|
49
|
+
<color code="blue" id="0">
|
50
|
+
blue
|
51
|
+
</color>
|
52
|
+
</color>
|
53
|
+
</color>
|
54
|
+
```
|
55
|
+
However, since the leaf nodes are generated first, and each leaf node does not know where it will appear in the final string, the tree data is built back-to-front and the tree needs to be constructed from the encoded string. Leaves can't attach themselves to parents that don't exist yet, but the resulting string contains information for each node's start/end points and its index in the stack.
|
56
|
+
|
57
|
+
## Color Code Tree Construction
|
58
|
+
|
59
|
+
Once the encoded string has been generated, a tree structure is built by identifying the start and end points of each substring, finding the largest non-overlapping ranges as 1st-generation children, and then repeating the same algorithm using each parent's boundaries to identify direct descendants, until no direct descendants exist (i.e. we have found a leaf node).
|
60
|
+
|
61
|
+
## Re-encoding into a colorized string
|
62
|
+
|
63
|
+
Once the final string has been decoded into a tree structure, each leaf node can inspect its parent to identify which color code should be restored. e.g. if a leaf node has color "yellow" and its parent has color "green", the resulting substring will start with the escape code for yellow, then the string's original value, then the escape code for green.
|
64
|
+
|
65
|
+
This process is repeated recursively back up the tree until the root is found, at which point the color is reset to the terminal's default.
|
66
|
+
|
67
|
+
## Summary
|
68
|
+
|
69
|
+
The constraints of using string interpolation to create nested colorized strings made developing _Paintbrush_ quite an interesting challenge. Each invocation of a color method receives only the string passed directly to it, and the return value of each method must be an object that _Ruby_ can interpolate into another string, removing the option to pass around objects with complex state and forcing everything to be encoded into the string.
|
70
|
+
|
71
|
+
The strings received to each call can be stored elsewhere, but the final string structure must define all start and end points of each colorization so that the stack can match each substring to a color code. As each string is received, it does not know where in the final string it will appear.
|
72
|
+
|
73
|
+
The result is what appears to be a robust model with unlimited nesting. Please [create an issue](https://github.com/bobf/paintbrush/issues) if you are able to break it.
|
74
|
+
|
75
|
+
```rspec:ansi
|
76
|
+
subject do
|
77
|
+
paintbrush do
|
78
|
+
"nesting with #{blue 'foo'} #{green "bar #{cyan "baz"} with #{cyan 'qux'} and quux"} and #{red "corge"}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it { is_expected.to include 'baz' }
|
83
|
+
```
|
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.3
|
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-
|
11
|
+
date: 2023-06-04 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,19 +28,32 @@ files:
|
|
28
28
|
- Rakefile
|
29
29
|
- doc/example.png
|
30
30
|
- lib/paintbrush.rb
|
31
|
-
- lib/
|
32
|
-
- lib/
|
33
|
-
- lib/
|
34
|
-
- lib/
|
35
|
-
- lib/
|
36
|
-
- lib/
|
37
|
-
- lib/
|
31
|
+
- lib/paintbrush_support/bounded_color_element.rb
|
32
|
+
- lib/paintbrush_support/color_element.rb
|
33
|
+
- lib/paintbrush_support/colorized_string.rb
|
34
|
+
- lib/paintbrush_support/colors.rb
|
35
|
+
- lib/paintbrush_support/configuration.rb
|
36
|
+
- lib/paintbrush_support/element_tree.rb
|
37
|
+
- lib/paintbrush_support/escapes.rb
|
38
|
+
- lib/paintbrush_support/hex_color_code.rb
|
39
|
+
- lib/paintbrush_support/version.rb
|
38
40
|
- paintbrush.gemspec
|
39
|
-
- rspec-documentation/
|
40
|
-
- rspec-documentation/pages/
|
41
|
+
- rspec-documentation/pages/000-Introduction.md
|
42
|
+
- rspec-documentation/pages/010-Colors.md
|
43
|
+
- rspec-documentation/pages/020-Examples.md
|
44
|
+
- rspec-documentation/pages/020-Examples/010-Basic Usage.md
|
45
|
+
- rspec-documentation/pages/020-Examples/020-Bright Colors.md
|
46
|
+
- rspec-documentation/pages/020-Examples/030-Nested Colors.md
|
47
|
+
- rspec-documentation/pages/020-Examples/040-RGB Colors.md
|
48
|
+
- rspec-documentation/pages/020-Examples/050-Dynamic Usage.md
|
49
|
+
- rspec-documentation/pages/020-Examples/060-Without Including.md
|
50
|
+
- rspec-documentation/pages/030-Configuration.md
|
51
|
+
- rspec-documentation/pages/040-How It Works.md
|
52
|
+
- rspec-documentation/spec_helper.rb
|
41
53
|
- sig/paintbrush.rbs
|
42
54
|
homepage: https://github.com/bobf/paintbrush
|
43
|
-
licenses:
|
55
|
+
licenses:
|
56
|
+
- MIT
|
44
57
|
metadata:
|
45
58
|
homepage_uri: https://github.com/bobf/paintbrush
|
46
59
|
source_code_uri: https://github.com/bobf/paintbrush
|
data/lib/paintbrush/colors.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Paintbrush
|
4
|
-
# Provides methods that are temporarily injected into block context. Each method returns an
|
5
|
-
# escaped string including the current stack size with start and end escape codes, allowing the
|
6
|
-
# string to be reconstituted afterwards with nested strings restoring the previous color once
|
7
|
-
# they have terminated.
|
8
|
-
module Colors
|
9
|
-
COLOR_CODES = {
|
10
|
-
black: '30',
|
11
|
-
red: '31',
|
12
|
-
green: '32',
|
13
|
-
yellow: '33',
|
14
|
-
blue: '34',
|
15
|
-
purple: '35',
|
16
|
-
cyan: '36',
|
17
|
-
white: '37',
|
18
|
-
default: '39'
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
COLOR_CODES.each do |name, code|
|
22
|
-
define_method name do |string|
|
23
|
-
ColorElement.new(stack: @__stack, code: code, string: string).to_s
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/paintbrush/version.rb
DELETED
@@ -1,312 +0,0 @@
|
|
1
|
-
<html>
|
2
|
-
<head>
|
3
|
-
<link rel="stylesheet"
|
4
|
-
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css"
|
5
|
-
integrity="sha512-SbiR/eusphKoMVVXysTKG/7VseWii+Y3FdHrt0EpKgpToZeemhqHeZeLWLhJutz/2ut2Vw1uQEj2MbRF+TVBUA=="
|
6
|
-
crossorigin="anonymous"
|
7
|
-
referrerpolicy="no-referrer" />
|
8
|
-
<style>
|
9
|
-
|
10
|
-
.code {
|
11
|
-
font-family: monospace;
|
12
|
-
max-height: 30rem;
|
13
|
-
overflow-y: auto;
|
14
|
-
}
|
15
|
-
|
16
|
-
h1.title {
|
17
|
-
display: inline;
|
18
|
-
}
|
19
|
-
|
20
|
-
.header .separator {
|
21
|
-
display: inline-block;
|
22
|
-
height: 2.5rem;
|
23
|
-
}
|
24
|
-
|
25
|
-
.version {
|
26
|
-
color: #bbb;
|
27
|
-
font-size: 2rem;
|
28
|
-
}
|
29
|
-
|
30
|
-
.ansi-html {
|
31
|
-
display: inline-block;
|
32
|
-
background-color: #2e2e2e;
|
33
|
-
border: 5px solid #2e2e2e;
|
34
|
-
border-radius: 10px;
|
35
|
-
}
|
36
|
-
|
37
|
-
.ansi-html .ansi-color-0 { color: #555555; }
|
38
|
-
.ansi-html .ansi-color-1 { color: #ff0000; }
|
39
|
-
.ansi-html .ansi-color-2 { color: #47ff47; }
|
40
|
-
.ansi-html .ansi-color-3 { color: #e9e947; }
|
41
|
-
.ansi-html .ansi-color-4 { color: #49a0dd; }
|
42
|
-
.ansi-html .ansi-color-5 { color: #8d7eeb; }
|
43
|
-
.ansi-html .ansi-color-6 { color: #2eecff; }
|
44
|
-
.ansi-html .ansi-color-7 { color: #ffffff; }
|
45
|
-
.ansi-html .ansi-color-9 { color: #606060; }
|
46
|
-
.ansi-html .ansi-color-reset { color: #dddddd; }
|
47
|
-
|
48
|
-
.highlight table td { padding: 5px; }
|
49
|
-
.highlight table pre { margin: 0; }
|
50
|
-
.highlight, .highlight .w {
|
51
|
-
color: #24292f;
|
52
|
-
background-color: #f6f8fa;
|
53
|
-
}
|
54
|
-
.highlight .k, .highlight .kd, .highlight .kn, .highlight .kp, .highlight .kr, .highlight .kt, .highlight .kv {
|
55
|
-
color: #cf222e;
|
56
|
-
}
|
57
|
-
.highlight .gr {
|
58
|
-
color: #f6f8fa;
|
59
|
-
}
|
60
|
-
.highlight .gd {
|
61
|
-
color: #82071e;
|
62
|
-
background-color: #ffebe9;
|
63
|
-
}
|
64
|
-
.highlight .nb {
|
65
|
-
color: #953800;
|
66
|
-
}
|
67
|
-
.highlight .nc {
|
68
|
-
color: #953800;
|
69
|
-
}
|
70
|
-
.highlight .no {
|
71
|
-
color: #953800;
|
72
|
-
}
|
73
|
-
.highlight .nn {
|
74
|
-
color: #953800;
|
75
|
-
}
|
76
|
-
.highlight .sr {
|
77
|
-
color: #116329;
|
78
|
-
}
|
79
|
-
.highlight .na {
|
80
|
-
color: #116329;
|
81
|
-
}
|
82
|
-
.highlight .nt {
|
83
|
-
color: #116329;
|
84
|
-
}
|
85
|
-
.highlight .gi {
|
86
|
-
color: #116329;
|
87
|
-
background-color: #dafbe1;
|
88
|
-
}
|
89
|
-
.highlight .kc {
|
90
|
-
color: #0550ae;
|
91
|
-
}
|
92
|
-
.highlight .l, .highlight .ld, .highlight .m, .highlight .mb, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il, .highlight .mo, .highlight .mx {
|
93
|
-
color: #0550ae;
|
94
|
-
}
|
95
|
-
.highlight .sb {
|
96
|
-
color: #0550ae;
|
97
|
-
}
|
98
|
-
.highlight .bp {
|
99
|
-
color: #0550ae;
|
100
|
-
}
|
101
|
-
.highlight .ne {
|
102
|
-
color: #0550ae;
|
103
|
-
}
|
104
|
-
.highlight .nl {
|
105
|
-
color: #0550ae;
|
106
|
-
}
|
107
|
-
.highlight .py {
|
108
|
-
color: #0550ae;
|
109
|
-
}
|
110
|
-
.highlight .nv, .highlight .vc, .highlight .vg, .highlight .vi, .highlight .vm {
|
111
|
-
color: #0550ae;
|
112
|
-
}
|
113
|
-
.highlight .o, .highlight .ow {
|
114
|
-
color: #0550ae;
|
115
|
-
}
|
116
|
-
.highlight .gh {
|
117
|
-
color: #0550ae;
|
118
|
-
font-weight: bold;
|
119
|
-
}
|
120
|
-
.highlight .gu {
|
121
|
-
color: #0550ae;
|
122
|
-
font-weight: bold;
|
123
|
-
}
|
124
|
-
.highlight .s, .highlight .sa, .highlight .sc, .highlight .dl, .highlight .sd, .highlight .s2, .highlight .se, .highlight .sh, .highlight .sx, .highlight .s1, .highlight .ss {
|
125
|
-
color: #0a3069;
|
126
|
-
}
|
127
|
-
.highlight .nd {
|
128
|
-
color: #8250df;
|
129
|
-
}
|
130
|
-
.highlight .nf, .highlight .fm {
|
131
|
-
color: #8250df;
|
132
|
-
}
|
133
|
-
.highlight .err {
|
134
|
-
color: #f6f8fa;
|
135
|
-
background-color: #82071e;
|
136
|
-
}
|
137
|
-
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cm, .highlight .cp, .highlight .cpf, .highlight .c1, .highlight .cs {
|
138
|
-
color: #6e7781;
|
139
|
-
}
|
140
|
-
.highlight .gl {
|
141
|
-
color: #6e7781;
|
142
|
-
}
|
143
|
-
.highlight .gt {
|
144
|
-
color: #6e7781;
|
145
|
-
}
|
146
|
-
.highlight .ni {
|
147
|
-
color: #24292f;
|
148
|
-
}
|
149
|
-
.highlight .si {
|
150
|
-
color: #24292f;
|
151
|
-
}
|
152
|
-
.highlight .ge {
|
153
|
-
color: #24292f;
|
154
|
-
font-style: italic;
|
155
|
-
}
|
156
|
-
.highlight .gs {
|
157
|
-
color: #24292f;
|
158
|
-
font-weight: bold;
|
159
|
-
}
|
160
|
-
|
161
|
-
</style>
|
162
|
-
</head>
|
163
|
-
|
164
|
-
<body>
|
165
|
-
<div class="container m-3 p-3">
|
166
|
-
<div class="header p-3 m-3 w-90 text-end">
|
167
|
-
<h1 class="title">paintbrush</h1>
|
168
|
-
<span class="separator border-end pb-2 ms-2 me-2"></span>
|
169
|
-
<span class="version">0.1.0</span>
|
170
|
-
</div>
|
171
|
-
|
172
|
-
<hr/>
|
173
|
-
|
174
|
-
|
175
|
-
<div class="row">
|
176
|
-
<div class="col-auto page-tree fs-6 mt-1 ms-3 me-3">
|
177
|
-
|
178
|
-
<li>
|
179
|
-
|
180
|
-
<a href='/home/bob/dev/paintbrush/rspec-documentation/bundle/introduction.html'>Introduction</a>
|
181
|
-
|
182
|
-
</li>
|
183
|
-
|
184
|
-
<ul>
|
185
|
-
|
186
|
-
</ul>
|
187
|
-
|
188
|
-
</div>
|
189
|
-
|
190
|
-
<div class="col">
|
191
|
-
<h1 id="paintbrush">Paintbrush</h1>
|
192
|
-
|
193
|
-
<p>Simple and concise string colorization for <em>Ruby</em> without overloading <code>String</code> methods or requiring verbose class/method invocation.</p>
|
194
|
-
|
195
|
-
<p><em>Paintbrush</em> has zero dependencies and does not pollute any namespaces or objects outside of the <code>#paintbrush</code> method wherever you include the <code>Paintbrush</code> module.</p>
|
196
|
-
|
197
|
-
<p>Nesting is supported, allowing you to use multiple colors within the same string. The previous color is automatically restored.</p>
|
198
|
-
|
199
|
-
<div location="9"><button type="button" class="btn btn-primary float-end" data-bs-toggle="modal" data-bs-target="#modal-15cae418-087d-45aa-b936-ea2c34033c01-side-by-side"> View Side-by-side </button> <div class="modal fade" id="modal-15cae418-087d-45aa-b936-ea2c34033c01-side-by-side" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
200
|
-
<div class="modal-dialog modal-xl">
|
201
|
-
<div class="modal-content">
|
202
|
-
<div class="modal-header">
|
203
|
-
<h5 class="modal-title" id="modal-15cae418-087d-45aa-b936-ea2c34033c01-side-by-side-label">Side-by-side view</h5>
|
204
|
-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
205
|
-
</div>
|
206
|
-
<div class="modal-body">
|
207
|
-
<div class="container p-3">
|
208
|
-
<div class="row border">
|
209
|
-
<div class="col border">
|
210
|
-
<div class="p-3 mb-5 code highlight">
|
211
|
-
<span class="nb">require</span> <span class="s1">'paintbrush'</span><br /><br /><span class="kp">extend</span> <span class="no">Paintbrush</span><br /><br /><span class="n">output</span> <span class="o">=</span> <span class="n">paintbrush</span> <span class="p">{</span> <span class="n">purple</span> <span class="s2">"You used </span><span class="si">#{</span><span class="n">green</span> <span class="s1">'four'</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">blue</span> <span class="s2">"(</span><span class="si">#{</span><span class="n">cyan</span> <span class="s1">'4'</span><span class="si">}</span><span class="s2">)"</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">yellow</span> <span class="s1">'colors'</span><span class="si">}</span><span class="s2"> today!"</span> <span class="p">}</span><br /><span class="n">it_documents</span> <span class="n">output</span> <span class="k">do</span><br /> <span class="n">expect</span><span class="p">(</span><span class="n">output</span><span class="p">).</span><span class="nf">to</span> <span class="n">eql</span> <span class="s2">"</span><span class="se">\e</span><span class="s2">[35mYou used </span><span class="se">\e</span><span class="s2">[32mfour</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m "</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[34m(</span><span class="se">\e</span><span class="s2">[36m4</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[34m)</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m "</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[33mcolors</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m today!</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m"</span><br /><span class="k">end</span><br />
|
212
|
-
</div>
|
213
|
-
</div>
|
214
|
-
<div class="col border">
|
215
|
-
<div class="p-3 mb-5 code highlight">
|
216
|
-
<div class="ansi-html border m-1 p-4">
|
217
|
-
<span></span><span class="ansi-color-5">You used </span><span class="ansi-color-2">four</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> </span><span class="ansi-color-4">(</span><span class="ansi-color-6">4</span><span class="ansi-color-reset"></span><span class="ansi-color-4">)</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> </span><span class="ansi-color-3">colors</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> today!</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"></span>
|
218
|
-
</div>
|
219
|
-
</div>
|
220
|
-
</div>
|
221
|
-
</div>
|
222
|
-
</div>
|
223
|
-
</div>
|
224
|
-
<div class="modal-footer">
|
225
|
-
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
226
|
-
</div>
|
227
|
-
</div>
|
228
|
-
</div>
|
229
|
-
</div>
|
230
|
-
<ul class="nav nav-tabs" id="html-tabs-15cae418-087d-45aa-b936-ea2c34033c01" role="tablist">
|
231
|
-
<li class="nav-item" role="presentation"><button class="nav-link active" id="code-source-15cae418-087d-45aa-b936-ea2c34033c01-tab" data-bs-toggle="tab" data-bs-target="#code-source-15cae418-087d-45aa-b936-ea2c34033c01" type="button" role="tab" aria-controls="code-source" aria-selected="true">Code</button></li>
|
232
|
-
<li class="nav-item" role="presentation"><button class="nav-link" id="rendered-15cae418-087d-45aa-b936-ea2c34033c01-tab" data-bs-toggle="tab" data-bs-target="#rendered-15cae418-087d-45aa-b936-ea2c34033c01" type="button" role="tab" aria-controls="rendered" aria-selected="false">Output</button></li>
|
233
|
-
</ul>
|
234
|
-
<div class="tab-content" id="html-tab-content-15cae418-087d-45aa-b936-ea2c34033c01">
|
235
|
-
<div class="tab-pane fade show active" id="code-source-15cae418-087d-45aa-b936-ea2c34033c01" role="tabpanel" aria-labelledby="code-source-15cae418-087d-45aa-b936-ea2c34033c01-tab">
|
236
|
-
<div class="p-3 mb-5 code highlight">
|
237
|
-
<span class="nb">require</span> <span class="s1">'paintbrush'</span><br /><br /><span class="kp">extend</span> <span class="no">Paintbrush</span><br /><br /><span class="n">output</span> <span class="o">=</span> <span class="n">paintbrush</span> <span class="p">{</span> <span class="n">purple</span> <span class="s2">"You used </span><span class="si">#{</span><span class="n">green</span> <span class="s1">'four'</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">blue</span> <span class="s2">"(</span><span class="si">#{</span><span class="n">cyan</span> <span class="s1">'4'</span><span class="si">}</span><span class="s2">)"</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">yellow</span> <span class="s1">'colors'</span><span class="si">}</span><span class="s2"> today!"</span> <span class="p">}</span><br /><span class="n">it_documents</span> <span class="n">output</span> <span class="k">do</span><br /> <span class="n">expect</span><span class="p">(</span><span class="n">output</span><span class="p">).</span><span class="nf">to</span> <span class="n">eql</span> <span class="s2">"</span><span class="se">\e</span><span class="s2">[35mYou used </span><span class="se">\e</span><span class="s2">[32mfour</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m "</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[34m(</span><span class="se">\e</span><span class="s2">[36m4</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[34m)</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m "</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[33mcolors</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[35m today!</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m"</span><br /><span class="k">end</span><br />
|
238
|
-
</div>
|
239
|
-
</div>
|
240
|
-
<div class="tab-pane fade" id="rendered-15cae418-087d-45aa-b936-ea2c34033c01" role="tabpanel" aria-labelledby="rendered-15cae418-087d-45aa-b936-ea2c34033c01-tab">
|
241
|
-
<div class="p-3 mb-5 code highlight">
|
242
|
-
<div class="ansi-html border m-1 p-4">
|
243
|
-
<span></span><span class="ansi-color-5">You used </span><span class="ansi-color-2">four</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> </span><span class="ansi-color-4">(</span><span class="ansi-color-6">4</span><span class="ansi-color-reset"></span><span class="ansi-color-4">)</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> </span><span class="ansi-color-3">colors</span><span class="ansi-color-reset"></span><span class="ansi-color-5"> today!</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"></span>
|
244
|
-
</div>
|
245
|
-
</div>
|
246
|
-
</div>
|
247
|
-
</div>
|
248
|
-
</div>
|
249
|
-
|
250
|
-
<div location="22"><button type="button" class="btn btn-primary float-end" data-bs-toggle="modal" data-bs-target="#modal-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-side-by-side"> View Side-by-side </button> <div class="modal fade" id="modal-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-side-by-side" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
251
|
-
<div class="modal-dialog modal-xl">
|
252
|
-
<div class="modal-content">
|
253
|
-
<div class="modal-header">
|
254
|
-
<h5 class="modal-title" id="modal-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-side-by-side-label">Side-by-side view</h5>
|
255
|
-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
256
|
-
</div>
|
257
|
-
<div class="modal-body">
|
258
|
-
<div class="container p-3">
|
259
|
-
<div class="row border">
|
260
|
-
<div class="col border">
|
261
|
-
<div class="p-3 mb-5 code highlight">
|
262
|
-
<span class="nb">require</span> <span class="s1">'paintbrush'</span><br /><br /><span class="kp">extend</span> <span class="no">Paintbrush</span><br /><br /><span class="n">output</span> <span class="o">=</span> <span class="n">paintbrush</span> <span class="k">do</span><br /> <span class="s2">"</span><span class="si">#{</span><span class="n">blue</span> <span class="s1">'foo'</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">green</span> <span class="s2">"bar </span><span class="si">#{</span><span class="n">cyan</span> <span class="sx">%w[foo bar baz]</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">', '</span><span class="p">)</span><span class="si">}</span><span class="s2"> with </span><span class="si">#{</span><span class="n">cyan</span> <span class="s1">'qux'</span><span class="si">}</span><span class="s2"> and quux"</span><span class="si">}</span><span class="s2"> and corge"</span><br /><span class="k">end</span><br /><br /><span class="n">it_documents</span> <span class="n">output</span> <span class="k">do</span><br /> <span class="n">expect</span><span class="p">(</span><span class="n">output</span><span class="p">).</span><span class="nf">to</span> <span class="n">eql</span> <span class="s2">"</span><span class="se">\e</span><span class="s2">[34mfoo</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m </span><span class="se">\e</span><span class="s2">[32mbar </span><span class="se">\e</span><span class="s2">[36mfoo, bar, baz"</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[32m with </span><span class="se">\e</span><span class="s2">[36mqux</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[32m "</span><span class="p">\</span><br /> <span class="s2">"and quux</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m and corge"</span><br /><span class="k">end</span><br />
|
263
|
-
</div>
|
264
|
-
</div>
|
265
|
-
<div class="col border">
|
266
|
-
<div class="p-3 mb-5 code highlight">
|
267
|
-
<div class="ansi-html border m-1 p-4">
|
268
|
-
<span></span><span class="ansi-color-4">foo</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"> </span><span class="ansi-color-2">bar </span><span class="ansi-color-6">foo, bar, baz</span><span class="ansi-color-reset"></span><span class="ansi-color-2"> with </span><span class="ansi-color-6">qux</span><span class="ansi-color-reset"></span><span class="ansi-color-2"> and quux</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"> and corge</span>
|
269
|
-
</div>
|
270
|
-
</div>
|
271
|
-
</div>
|
272
|
-
</div>
|
273
|
-
</div>
|
274
|
-
</div>
|
275
|
-
<div class="modal-footer">
|
276
|
-
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
277
|
-
</div>
|
278
|
-
</div>
|
279
|
-
</div>
|
280
|
-
</div>
|
281
|
-
<ul class="nav nav-tabs" id="html-tabs-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0" role="tablist">
|
282
|
-
<li class="nav-item" role="presentation"><button class="nav-link active" id="code-source-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-tab" data-bs-toggle="tab" data-bs-target="#code-source-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0" type="button" role="tab" aria-controls="code-source" aria-selected="true">Code</button></li>
|
283
|
-
<li class="nav-item" role="presentation"><button class="nav-link" id="rendered-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-tab" data-bs-toggle="tab" data-bs-target="#rendered-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0" type="button" role="tab" aria-controls="rendered" aria-selected="false">Output</button></li>
|
284
|
-
</ul>
|
285
|
-
<div class="tab-content" id="html-tab-content-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0">
|
286
|
-
<div class="tab-pane fade show active" id="code-source-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0" role="tabpanel" aria-labelledby="code-source-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-tab">
|
287
|
-
<div class="p-3 mb-5 code highlight">
|
288
|
-
<span class="nb">require</span> <span class="s1">'paintbrush'</span><br /><br /><span class="kp">extend</span> <span class="no">Paintbrush</span><br /><br /><span class="n">output</span> <span class="o">=</span> <span class="n">paintbrush</span> <span class="k">do</span><br /> <span class="s2">"</span><span class="si">#{</span><span class="n">blue</span> <span class="s1">'foo'</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">green</span> <span class="s2">"bar </span><span class="si">#{</span><span class="n">cyan</span> <span class="sx">%w[foo bar baz]</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">', '</span><span class="p">)</span><span class="si">}</span><span class="s2"> with </span><span class="si">#{</span><span class="n">cyan</span> <span class="s1">'qux'</span><span class="si">}</span><span class="s2"> and quux"</span><span class="si">}</span><span class="s2"> and corge"</span><br /><span class="k">end</span><br /><br /><span class="n">it_documents</span> <span class="n">output</span> <span class="k">do</span><br /> <span class="n">expect</span><span class="p">(</span><span class="n">output</span><span class="p">).</span><span class="nf">to</span> <span class="n">eql</span> <span class="s2">"</span><span class="se">\e</span><span class="s2">[34mfoo</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m </span><span class="se">\e</span><span class="s2">[32mbar </span><span class="se">\e</span><span class="s2">[36mfoo, bar, baz"</span> <span class="p">\</span><br /> <span class="s2">"</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[32m with </span><span class="se">\e</span><span class="s2">[36mqux</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[32m "</span><span class="p">\</span><br /> <span class="s2">"and quux</span><span class="se">\e</span><span class="s2">[0m</span><span class="se">\e</span><span class="s2">[0m and corge"</span><br /><span class="k">end</span><br />
|
289
|
-
</div>
|
290
|
-
</div>
|
291
|
-
<div class="tab-pane fade" id="rendered-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0" role="tabpanel" aria-labelledby="rendered-c3e2bbb8-9a13-4400-93a1-0e6c9847cba0-tab">
|
292
|
-
<div class="p-3 mb-5 code highlight">
|
293
|
-
<div class="ansi-html border m-1 p-4">
|
294
|
-
<span></span><span class="ansi-color-4">foo</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"> </span><span class="ansi-color-2">bar </span><span class="ansi-color-6">foo, bar, baz</span><span class="ansi-color-reset"></span><span class="ansi-color-2"> with </span><span class="ansi-color-6">qux</span><span class="ansi-color-reset"></span><span class="ansi-color-2"> and quux</span><span class="ansi-color-reset"></span><span class="ansi-color-reset"> and corge</span>
|
295
|
-
</div>
|
296
|
-
</div>
|
297
|
-
</div>
|
298
|
-
</div>
|
299
|
-
</div>
|
300
|
-
|
301
|
-
</div>
|
302
|
-
</div>
|
303
|
-
<hr/>
|
304
|
-
|
305
|
-
</div>
|
306
|
-
|
307
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js"
|
308
|
-
integrity="sha512-i9cEfJwUwViEPFKdC1enz4ZRGBj8YQo6QByFTF92YXHi7waCqyexvRD75S5NVTsSiTv7rKWqG9Y5eFxmRsOn0A=="
|
309
|
-
crossorigin="anonymous"
|
310
|
-
referrerpolicy="no-referrer"></script>
|
311
|
-
</body>
|
312
|
-
</html>
|
@@ -1,36 +0,0 @@
|
|
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
|
-
```
|