paintbrush 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7c87f82d4c60332bb80901c9b53ba99d027190044b8b6a8a0d91f0577c870846
4
+ data.tar.gz: cb1e9bd1e7c4fc0b65ac0ae6e50ce02dd62e86d7845192b1b14d18a602f069ce
5
+ SHA512:
6
+ metadata.gz: 21bacc0759c545c65c66d70e0fbdb7b406ea1fa224ebcab36e02d9f82ba4e4c0bdbb33dc34f61f52224272ee8c49cae3641d7ca48fdaf0bd5278ae3a3fdf6b08
7
+ data.tar.gz: a1340e727fe19c354cb5ae43202afe2ddfbdb94d8748cb8cba16edac3c1d88f3293e6825156c65043329d81f84a78ae041adc6e7d99fad52d64fe8cfe5513ea6
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ NewCops: enable
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.8
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in paintbrush.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ gem 'devpack', '~> 0.4.1'
11
+ gem 'rspec', '~> 3.0'
12
+ gem 'rubocop', '~> 1.51'
13
+ gem 'rubocop-rake', '~> 0.6.0'
14
+ gem 'rubocop-rspec', '~> 2.22'
15
+ gem 'strong_versions', '~> 0.4.5'
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ paintbrush (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ concurrent-ruby (1.2.2)
11
+ devpack (0.4.1)
12
+ diff-lcs (1.5.0)
13
+ i18n (1.13.0)
14
+ concurrent-ruby (~> 1.0)
15
+ json (2.6.3)
16
+ paint (2.3.0)
17
+ parallel (1.23.0)
18
+ parser (3.2.2.1)
19
+ ast (~> 2.4.1)
20
+ rainbow (3.1.1)
21
+ rake (13.0.6)
22
+ regexp_parser (2.8.0)
23
+ rexml (3.2.5)
24
+ rspec (3.12.0)
25
+ rspec-core (~> 3.12.0)
26
+ rspec-expectations (~> 3.12.0)
27
+ rspec-mocks (~> 3.12.0)
28
+ rspec-core (3.12.2)
29
+ rspec-support (~> 3.12.0)
30
+ rspec-expectations (3.12.3)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.12.0)
33
+ rspec-mocks (3.12.5)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.12.0)
36
+ rspec-support (3.12.0)
37
+ rubocop (1.51.0)
38
+ json (~> 2.3)
39
+ parallel (~> 1.10)
40
+ parser (>= 3.2.0.0)
41
+ rainbow (>= 2.2.2, < 4.0)
42
+ regexp_parser (>= 1.8, < 3.0)
43
+ rexml (>= 3.2.5, < 4.0)
44
+ rubocop-ast (>= 1.28.0, < 2.0)
45
+ ruby-progressbar (~> 1.7)
46
+ unicode-display_width (>= 2.4.0, < 3.0)
47
+ rubocop-ast (1.28.1)
48
+ parser (>= 3.2.1.0)
49
+ rubocop-capybara (2.18.0)
50
+ rubocop (~> 1.41)
51
+ rubocop-factory_bot (2.23.1)
52
+ rubocop (~> 1.33)
53
+ rubocop-rake (0.6.0)
54
+ rubocop (~> 1.0)
55
+ rubocop-rspec (2.22.0)
56
+ rubocop (~> 1.33)
57
+ rubocop-capybara (~> 2.17)
58
+ rubocop-factory_bot (~> 2.22)
59
+ ruby-progressbar (1.13.0)
60
+ strong_versions (0.4.5)
61
+ i18n (>= 0.5)
62
+ paint (~> 2.0)
63
+ unicode-display_width (2.4.2)
64
+
65
+ PLATFORMS
66
+ x86_64-linux
67
+
68
+ DEPENDENCIES
69
+ devpack (~> 0.4.1)
70
+ paintbrush!
71
+ rake (~> 13.0)
72
+ rspec (~> 3.0)
73
+ rubocop (~> 1.51)
74
+ rubocop-rake (~> 0.6.0)
75
+ rubocop-rspec (~> 2.22)
76
+ strong_versions (~> 0.4.5)
77
+
78
+ BUNDLED WITH
79
+ 2.4.12
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2023 Robert Farrell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,5 @@
1
+ .PHONY: test
2
+ test:
3
+ bundle exec rspec
4
+ bundle exec rubocop
5
+ bundle exec strong_versions
data/README.md ADDED
@@ -0,0 +1,78 @@
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
+ ```ruby
10
+ include Paintbrush
11
+ puts paintbrush { purple "You used #{green 'four'} #{blue "(#{cyan '4'})"} #{yellow 'colors'} today!" }
12
+ ```
13
+ ![example](doc/example.png "Example")
14
+
15
+ ## Installation
16
+
17
+ Add _Paintbrush_ to your `Gemfile`:
18
+
19
+ ```ruby
20
+ gem 'paintbrush'
21
+ ```
22
+
23
+ Build your bundle:
24
+
25
+ ```ruby
26
+ bundle install
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Include the `Paintbrush` module anywhere and call `#paintbrush` to generate a colorized string. Nested strings are supported, allowing many complex combinations to be written in a single line.
32
+
33
+ `#paintbrush` receives a block, within the block the following methods are available, each of which receives a string:
34
+
35
+ * `#black`
36
+ * `#red`
37
+ * `#green`
38
+ * `#yellow`
39
+ * `#blue`
40
+ * `#purple`
41
+ * `#cyan`
42
+ * `#white`
43
+ * `#default`
44
+
45
+ Use [string interpolation](https://docs.ruby-lang.org/en/3.2/syntax/literals_rdoc.html#label-String+Literals) to nest multiple colors:
46
+
47
+ ```ruby
48
+ include Paintbrush
49
+ puts paintbrush { green "some green text, #{yellow "some yellow text"} and some green again" }
50
+ ```
51
+
52
+ ## Alternatives
53
+
54
+ * [Colorize](https://github.com/fazibear/colorize)
55
+ * [Rainbow](https://github.com/sickill/rainbow)
56
+ * [Paint](https://github.com/janlelis/paint)
57
+
58
+ And [many others](https://www.ruby-toolbox.com/search?display=compact&order=score&q=string%20color&show_forks=false).
59
+
60
+ ## Motivation
61
+
62
+ There are plenty of gems that solve this problem in various ways but I was unable to find one that achieves all of the following:
63
+
64
+ * Support for nested strings.
65
+ * No pollution of _Ruby_ `String` objects.
66
+ * Concise syntax allowing strings to be generated in-line.
67
+
68
+ This gem is an attempt to achieve all of the above. If it's not for you, take a look at one of the alternatives (see above).
69
+
70
+ ## Development
71
+
72
+ Make a pull request to fix a bug or add a feature.
73
+
74
+ Run `make test` to verify all tests and lint checks have passed.
75
+
76
+ ## License
77
+
78
+ _Paintbrush_ is released under the [MIT License](https://opensource.org/license/mit/).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/doc/example.png ADDED
Binary file
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paintbrush
4
+ # Core string colorization, provides various methods for colorizing a string, uses escape
5
+ # sequences to store references to start and end of each coloring method to allow nested
6
+ # colorizing with string interpolation within each individual call to `paintbrush`.
7
+ class ColorizedString
8
+ def initialize(&block)
9
+ @block = block
10
+ @codes = []
11
+ end
12
+
13
+ # Returns a colorized string by injecting escape codes into the various calls to each color
14
+ # method in the provided block, rebuilds the string and returns the value with regular ANSI
15
+ # color codes ready to be output to a console.
16
+ def colorized
17
+ colorized_string
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :block, :codes
23
+
24
+ def colorized_string
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)
28
+ end
29
+ end
30
+
31
+ def subbed_string(string, index, code, restored_color_code)
32
+ string
33
+ .sub("#{Colors::ESCAPE_START_OPEN}#{index}#{Colors::ESCAPE_START_CLOSE}", "\e[#{code}m")
34
+ .sub("#{Colors::ESCAPE_END_OPEN}#{index}#{Colors::ESCAPE_END_CLOSE}", "\e[0m\e[#{restored_color_code}m")
35
+ end
36
+
37
+ def escaped_output
38
+ context.instance_eval(&block)
39
+ end
40
+
41
+ def context
42
+ eval('self', block.binding, __FILE__, __LINE__).dup.tap do |context|
43
+ context.send(:include, Paintbrush::Colors) if context.respond_to?(:include)
44
+ context.send(:extend, Paintbrush::Colors) if context.respond_to?(:extend)
45
+ context.send(:instance_variable_set, :@__codes, codes)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
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
+ 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
+ COLOR_CODES = {
15
+ black: '30',
16
+ red: '31',
17
+ green: '32',
18
+ yellow: '33',
19
+ blue: '34',
20
+ purple: '35',
21
+ cyan: '36',
22
+ white: '37',
23
+ default: '39'
24
+ }.freeze
25
+
26
+ COLOR_CODES.each do |name, code|
27
+ define_method name do |string|
28
+ @__codes.push(code)
29
+ "#{ESCAPE_START_OPEN}#{@__codes.size - 1}#{ESCAPE_START_CLOSE}" \
30
+ "#{string}" \
31
+ "#{ESCAPE_END_OPEN}#{@__codes.size - 1}#{ESCAPE_END_CLOSE}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paintbrush
4
+ VERSION = '0.1.0'
5
+ end
data/lib/paintbrush.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'paintbrush/version'
4
+ require_relative 'paintbrush/colors'
5
+ require_relative 'paintbrush/colorized_string'
6
+
7
+ # Colorizes a string, provides `#paintbrush`. When included/extended in a class, call
8
+ # `#paintbrush` and pass a block to use the provided dynamically defined methods, e.g.:
9
+ #
10
+ # ```ruby
11
+ # class Foo
12
+ # include Paintbrush
13
+ #
14
+ # def bar
15
+ # puts paintbrush { cyan("hello #{green("there")}) }
16
+ # end
17
+ # ```
18
+ module Paintbrush
19
+ class Error < StandardError; end
20
+
21
+ def paintbrush(&block)
22
+ ColorizedString.new(&block).colorized
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/paintbrush/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'paintbrush'
7
+ spec.version = Paintbrush::VERSION
8
+ spec.authors = ['Bob Farrell']
9
+ spec.email = ['git@bob.frl']
10
+
11
+ spec.summary = 'Hassle-free text coloring for console applications.'
12
+ spec.description = 'Provides a set of encapsulated methods for nested colorization of strings.'
13
+ spec.homepage = 'https://github.com/bobf/paintbrush'
14
+ spec.required_ruby_version = '>= 2.7.0'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = spec.homepage
18
+ spec.metadata['changelog_uri'] = spec.homepage
19
+
20
+ spec.files = Dir.chdir(__dir__) do
21
+ `git ls-files -z`.split("\x0").reject do |f|
22
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
23
+ end
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+ spec.metadata['rubygems_mfa_required'] = 'true'
29
+ end
@@ -0,0 +1,4 @@
1
+ module Paintbrush
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paintbrush
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Bob Farrell
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-05-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Provides a set of encapsulated methods for nested colorization of strings.
14
+ email:
15
+ - git@bob.frl
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - ".rubocop.yml"
22
+ - ".ruby-version"
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - LICENSE
26
+ - Makefile
27
+ - README.md
28
+ - Rakefile
29
+ - doc/example.png
30
+ - lib/paintbrush.rb
31
+ - lib/paintbrush/colorized_string.rb
32
+ - lib/paintbrush/colors.rb
33
+ - lib/paintbrush/version.rb
34
+ - paintbrush.gemspec
35
+ - sig/paintbrush.rbs
36
+ homepage: https://github.com/bobf/paintbrush
37
+ licenses: []
38
+ metadata:
39
+ homepage_uri: https://github.com/bobf/paintbrush
40
+ source_code_uri: https://github.com/bobf/paintbrush
41
+ changelog_uri: https://github.com/bobf/paintbrush
42
+ rubygems_mfa_required: 'true'
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 2.7.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.1.6
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Hassle-free text coloring for console applications.
62
+ test_files: []