pastel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: df0d822f2378510e2c8f751d179c208585fb2e38
4
+ data.tar.gz: bf0a8a93193af9c35ff862e0e69373d97bf29d51
5
+ SHA512:
6
+ metadata.gz: 7dcf28176858eeaccc03eb33d702214274e72d32082887d66938afa1f7d6f38b24fa7523437ed4249d51e6c7425db729e42ad50cd83daf0747ea953abb96157c
7
+ data.tar.gz: c6a17854cb0c7328474da74d4c8ffee8f0af6c757f729bbef91ec02da7202e91d4da108ef318be8dcf4ab51e1fa20a9985cd8e3ed35c4f5f50db3de7e888488d
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ pastel
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/.travis.yml ADDED
@@ -0,0 +1,24 @@
1
+ language: ruby
2
+ bundler_args: --without yard benchmarks
3
+ script: "bundle exec rake ci"
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - ruby-head
9
+ matrix:
10
+ include:
11
+ - rvm: jruby-19mode
12
+ - rvm: jruby-20mode
13
+ - rvm: jruby-21mode
14
+ - rvm: jruby-head
15
+ - rvm: rbx-2
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
19
+ - rvm: jruby-20mode
20
+ - rvm: jruby-21mode
21
+ - rvm: rbx-2
22
+ fast_finish: true
23
+ branches:
24
+ only: master
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake', '~> 10.3.2'
7
+ gem 'rspec', '~> 3.1.0'
8
+ gem 'yard', '~> 0.8.7'
9
+ end
10
+
11
+ group :metrics do
12
+ gem 'coveralls', '~> 0.7.0'
13
+ gem 'simplecov', '~> 0.8.2'
14
+ gem 'yardstick', '~> 0.9.9'
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Piotr Murach
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # Pastel
2
+ [![Gem Version](https://badge.fury.io/rb/pastel.png)][gem]
3
+ [![Build Status](https://secure.travis-ci.org/peter-murach/pastel.png?branch=master)][travis]
4
+ [![Code Climate](https://codeclimate.com/github/peter-murach/pastel.png)][codeclimate]
5
+
6
+ [gem]: http://badge.fury.io/rb/pastel
7
+ [travis]: http://travis-ci.org/peter-murach/pastel
8
+ [codeclimate]: https://codeclimate.com/github/peter-murach/pastel
9
+
10
+ Terminal output styling with intuitive and clean API that doesn't monkey patch String class.
11
+
12
+ **Pastel** is minimal and focused to work in all terminal emulators.
13
+
14
+ ## Features
15
+
16
+ * Doesn't monkey patch `String`
17
+ * Intuitive and expressive API
18
+ * Minimal and focused to work on all terminal emulators
19
+ * Auto-detection of color support
20
+ * Performant
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'pastel'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install pastel
35
+
36
+ ## Contents
37
+
38
+ * [1. Usage](#1-usage)
39
+ * [2. Interface](#2-interface)
40
+ * [2.1 Color](#21-color)
41
+ * [2.2 Decorate](#22-decorate)
42
+ * [2.3 Strip](#23-strip)
43
+ * [2.4 Styles](#24-styles)
44
+ * [2.5 Valid?](#25-valid)
45
+ * [3. The available styles](#3-the-available-styles)
46
+
47
+ ## 1 Usage
48
+
49
+ **Pastel** provides a simple, minimal and intuitive API for styling your strings:
50
+
51
+ ```ruby
52
+ pastel = Pastel.new
53
+
54
+ pastel.red('Unicorns!')
55
+ ```
56
+
57
+ It allows you to combine styled strings with regular ones:
58
+
59
+ ```ruby
60
+ pastel.red('Unicorns') + ' will rule ' + pastel.green('the World!')
61
+ ```
62
+
63
+ You can compose multiple styles through chainable API:
64
+
65
+ ```ruby
66
+ pastel.red.on_green.bold('Unicorns!')
67
+ ```
68
+
69
+ It supports variable number of arguments with individual styling:
70
+
71
+ ```ruby
72
+ pastel.red('Unicorns', 'are', 'running', 'everywhere!')
73
+ ```
74
+
75
+ You can also nest styles as follows:
76
+
77
+ ```ruby
78
+ pastel.red('Unicorns ', pastel.on_green('everywhere!'))
79
+ ```
80
+
81
+ ## 2 Interface
82
+
83
+ ### 2.1 Color
84
+
85
+ You can pass variable number of styled strings like so:
86
+
87
+ ```ruby
88
+ pastel.red('Unicorns', pastel.on_yellow('are running', pastel.bold.underline('everywhere')), '!')
89
+ ```
90
+
91
+ Please refer to [3. The available styles](#3-the-available-styles) section for full list of supported styles.
92
+
93
+ ### 2.2 Decorate
94
+
95
+ This method is a lower level string styling call that takes as the first argument the string to style and any number of attributes, and returns string wrapped in styles.
96
+
97
+ ```ruby
98
+ pastel.decorate('Unicorn', :green, :on_blue, :bold)
99
+ ```
100
+
101
+ ### 2.3 Strip
102
+
103
+ Strip all color sequence characters:
104
+
105
+ ```ruby
106
+ pastel.strip("\e[1m\e[34mbold blue text\e[0m"") # => "bold blue text"
107
+ ```
108
+
109
+ ### 2.4 Styles
110
+
111
+ To get a full list of supported styles with the corresponding color codes do:
112
+
113
+ ```ruby
114
+ pastel.styles
115
+ ```
116
+
117
+ ### 2.5 Valid?
118
+
119
+ Determine whether a color is valid:
120
+
121
+ ```ruby
122
+ pastel.valid?(:red) # => true
123
+ pastel.valid?(:unicorn) # => false
124
+ ```
125
+
126
+ ## 3 The available styles
127
+
128
+ **Pastel** works with terminal emulators that support minimum sixteen colors. It provides `16` basic colors and `8` styles with further `16` bright color pairs. The corresponding bright color is obtained by prepending the `bright` to the normal color name. For example, color `red` will have `bright_red` as its pair.
129
+
130
+ The variant with `on_` prefix will style the text background color.
131
+
132
+ The foreground colors:
133
+
134
+ * `black`
135
+ * `red`
136
+ * `green`
137
+ * `yellow`
138
+ * `blue`
139
+ * `magenta`
140
+ * `cyan`
141
+ * `white`
142
+ * `bright_black`
143
+ * `bright_red`
144
+ * `bright_green`
145
+ * `bright_yellow`
146
+ * `bright_blue`
147
+ * `bright_magenta`
148
+ * `bright_cyan`
149
+ * `bright_white`
150
+
151
+ The background colors:
152
+
153
+ * `on_black`
154
+ * `on_red`
155
+ * `on_green`
156
+ * `on_yellow`
157
+ * `on_blue`
158
+ * `on_magenta`
159
+ * `on_cyan`
160
+ * `on_white`
161
+ * `on_bright_black`
162
+ * `on_bright_red`
163
+ * `on_bright_green`
164
+ * `on_bright_yellow`
165
+ * `on_bright_blue`
166
+ * `on_bright_magenta`
167
+ * `on_bright_cyan`
168
+ * `on_bright_white`
169
+
170
+ Generic styles:
171
+
172
+ * `clear`
173
+ * `bold`
174
+ * `dim`
175
+ * `italic`
176
+ * `underline`
177
+ * `inverse`
178
+ * `hidden`
179
+ * `strikethrough`
180
+
181
+ ## Contributing
182
+
183
+ 1. Fork it ( https://github.com/[my-github-username]/pastel/fork )
184
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
185
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
186
+ 4. Push to the branch (`git push origin my-new-feature`)
187
+ 5. Create a new Pull Request
188
+
189
+ ## Copyright
190
+
191
+ Copyright (c) 2014 Piotr Murach. See LICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ FileList['tasks/**/*.rake'].each(&method(:import))
6
+
7
+ desc 'Run all specs'
8
+ task ci: %w[ spec ]
data/lib/pastel.rb ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ require 'equatable'
4
+ require 'pastel/ansi'
5
+ require 'pastel/color'
6
+ require 'pastel/color_resolver'
7
+ require 'pastel/delegator'
8
+ require 'pastel/decorator_chain'
9
+ require 'pastel/version'
10
+
11
+ module Pastel
12
+ # Raised when the style attribute is not supported
13
+ InvalidAttributeNameError = Class.new(::ArgumentError)
14
+
15
+ def new
16
+ Delegator.for(DecoratorChain.empty)
17
+ end
18
+
19
+ module_function :new
20
+ end # Pastel
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ module Pastel
4
+ # Mixin that provides ANSI codes
5
+ module ANSI
6
+ CLEAR = "\e[0m"
7
+
8
+ BOLD = "\e[1m"
9
+ DIM = "\e[2m"
10
+ ITALIC = "\e[3m"
11
+ UNDERLINE = "\e[4m"
12
+ INVERSE = "\e[7m"
13
+ HIDDEN = "\e[8m"
14
+ STRIKETHROUGH = "\e[9m"
15
+
16
+ # Escape codes for text color.
17
+ BLACK = "\e[30m"
18
+ RED = "\e[31m"
19
+ GREEN = "\e[32m"
20
+ YELLOW = "\e[33m"
21
+ BLUE = "\e[34m"
22
+ MAGENTA = "\e[35m"
23
+ CYAN = "\e[36m"
24
+ WHITE = "\e[37m"
25
+
26
+ BRIGHT_BLACK = "\e[90m"
27
+ BRIGHT_RED = "\e[91m"
28
+ BRIGHT_GREEN = "\e[92m"
29
+ BRIGHT_YELLOW = "\e[93m"
30
+ BRIGHT_BLUE = "\e[94m"
31
+ BRIGHT_MAGENTA = "\e[95m"
32
+ BRIGHT_CYAN = "\e[96m"
33
+
34
+ # Escape codes for background color.
35
+ ON_BLACK = "\e[40m"
36
+ ON_RED = "\e[41m"
37
+ ON_GREEN = "\e[42m"
38
+ ON_YELLOW = "\e[43m"
39
+ ON_BLUE = "\e[44m"
40
+ ON_MAGENTA = "\e[45m"
41
+ ON_CYAN = "\e[46m"
42
+ ON_WHITE = "\e[47m"
43
+
44
+ ON_BRIGHT_BLACK = "\e[100m"
45
+ ON_BRIGHT_RED = "\e[101m"
46
+ ON_BRIGHT_GREEN = "\e[102m"
47
+ ON_BRIGHT_YELLOW = "\e[103m"
48
+ ON_BRIGHT_BLUE = "\e[104m"
49
+ ON_BRIGHT_MAGENTA = "\e[105m"
50
+ ON_BRIGHT_CYAN = "\e[106m"
51
+
52
+ BACKGROUND_COLORS = constants.grep(/^ON_*/).freeze
53
+ end # ANSI
54
+ end # Pastel
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ module Pastel
4
+ # A class responsible for coloring strings.
5
+ class Color
6
+ include Equatable
7
+ include ANSI
8
+
9
+ attr_reader :enabled
10
+
11
+ # Initialize a Terminal Color
12
+ #
13
+ # @api public
14
+ def initialize(enabled = false)
15
+ @enabled = enabled
16
+ end
17
+
18
+ # Disable coloring of this terminal session
19
+ #
20
+ # @api public
21
+ def disable!
22
+ @enabled = false
23
+ end
24
+
25
+ # Apply ANSI color to the given string.
26
+ #
27
+ # @param [String] string
28
+ # text to add ANSI strings
29
+ #
30
+ # @param [Array[Symbol]] colors
31
+ #
32
+ # @example
33
+ # color.decorate "text", :yellow, :on_green, :underline
34
+ #
35
+ # @return [String]
36
+ #
37
+ # @api public
38
+ def decorate(string, *colors)
39
+ return string if string.empty?
40
+ validate(*colors)
41
+ ansi_colors = colors.map { |color| lookup(color) }
42
+ ansi_string = "#{ansi_colors.join}#{string}#{ANSI::CLEAR}"
43
+ if ansi_string =~ /(#{Regexp.quote(ANSI::CLEAR)}){2,}/
44
+ ansi_string.gsub!(/(#{Regexp.quote(ANSI::CLEAR)}){2,}/, '')
45
+ end
46
+ matches = ansi_string.scan(/#{Regexp.quote(ANSI::CLEAR)}/)
47
+ if matches.length >= 2
48
+ ansi_string.sub!(/#{Regexp.quote(ANSI::CLEAR)}/, ansi_colors.join)
49
+ end
50
+ ansi_string
51
+ end
52
+
53
+ # Same as instance method.
54
+ #
55
+ # @return [String]
56
+ #
57
+ # @api public
58
+ def self.decorate(string, *colors)
59
+ new.decorate(string, *colors)
60
+ end
61
+
62
+ # Strip ANSI color codes from a string.
63
+ #
64
+ # @param [String] string
65
+ #
66
+ # @return [String]
67
+ #
68
+ # @api public
69
+ def strip(string)
70
+ string.to_s.gsub(/(\[)?\033(\[)?[;?\d]*[\dA-Za-z](\])?/, '')
71
+ end
72
+
73
+ # Return raw color code without embeding it into a string.
74
+ #
75
+ # @return [Array[String]]
76
+ # ANSI escape codes
77
+ #
78
+ # @api public
79
+ def code(*colors)
80
+ validate(*colors)
81
+ colors.map { |color| lookup(color) }
82
+ end
83
+
84
+ # Find color representation.
85
+ #
86
+ # @param [Symbol,String] color
87
+ # the color name to lookup by
88
+ #
89
+ # @return [String]
90
+ # the ANSI code
91
+ #
92
+ # @api private
93
+ def lookup(color)
94
+ self.class.const_get(color.to_s.upcase)
95
+ end
96
+
97
+ # Expose all ANSI color names and their codes
98
+ #
99
+ # @return [Hash[Symbol]]
100
+ #
101
+ # @api public
102
+ def styles
103
+ ANSI.constants(false).each_with_object({}) do |col, acc|
104
+ acc[col.to_sym.downcase] = lookup(col)
105
+ acc
106
+ end
107
+ end
108
+
109
+ # List all available style names
110
+ #
111
+ # @return [Array[Symbol]]
112
+ #
113
+ # @api public
114
+ def style_names
115
+ styles.keys
116
+ end
117
+
118
+ # Check if provided colors are known colors
119
+ #
120
+ # @param [Array[Symbol,String]]
121
+ # the colors to check
122
+ #
123
+ # @reutrn [Boolean]
124
+ #
125
+ # @api public
126
+ def valid?(*colors)
127
+ colors.all? { |color| style_names.include?(color.to_sym) }
128
+ end
129
+
130
+ protected
131
+
132
+ # @api private
133
+ def validate(*colors)
134
+ return if valid?(*colors)
135
+ fail InvalidAttributeNameError, 'Bad style or unintialized constant, ' \
136
+ " valid styles are: #{style_names.join(', ')}."
137
+ end
138
+ end # Color
139
+ end # TTY
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+
3
+ module Pastel
4
+ # Contains logic for resolving styles applied to component
5
+ #
6
+ # Used internally by {Delegator}.
7
+ #
8
+ # @api private
9
+ class ColorResolver
10
+ attr_reader :color
11
+
12
+ def initialize(color = Color.new)
13
+ @color = color
14
+ end
15
+
16
+ def resolve(base, *args)
17
+ unprocessed_string = args.join
18
+ base.reduce(unprocessed_string) do |component, decorator|
19
+ color.decorate(component, decorator)
20
+ end
21
+ end
22
+ end # ColorResolver
23
+ end # Pastel
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+
3
+ module Pastel
4
+ # Collects a list of decorators for styling a string
5
+ #
6
+ # @api private
7
+ class DecoratorChain
8
+ include Enumerable
9
+ include Equatable
10
+
11
+ attr_reader :decorators
12
+
13
+ def initialize(decorators = [])
14
+ @decorators = decorators
15
+ end
16
+
17
+ # Add decorator
18
+ #
19
+ # @api public
20
+ def add(decorator)
21
+ self.class.new(decorators + [decorator])
22
+ end
23
+
24
+ # Iterate over list of decorators
25
+ #
26
+ # @api public
27
+ def each(&block)
28
+ decorators.each(&block)
29
+ end
30
+
31
+ # Create an empty decorator chain
32
+ #
33
+ # @return [DecoratorChain]
34
+ #
35
+ # @api public
36
+ def self.empty
37
+ new([])
38
+ end
39
+ end # DecoratorChain
40
+ end # Patel
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+
3
+ module Pastel
4
+ # Wrapes the {DecoratorChain} to allow for easy resolution
5
+ # of string coloring.
6
+ #
7
+ # @api private
8
+ class Delegator
9
+ extend Forwardable
10
+
11
+ attr_reader :base
12
+
13
+ attr_reader :resolver
14
+
15
+ def_delegators :@color, :valid?, :styles, :strip, :decorate
16
+
17
+ def initialize(base)
18
+ @base = base
19
+ @color = Color.new
20
+ @resolver = ColorResolver.new(@color)
21
+ end
22
+
23
+ # @api public
24
+ def self.for(value)
25
+ new(value)
26
+ end
27
+
28
+ protected
29
+
30
+ def method_missing(method_name, *args, &block)
31
+ new_base = base.add(method_name)
32
+ delegator = self.class.new(new_base)
33
+ if args.empty?
34
+ delegator
35
+ else
36
+ resolver.resolve(new_base, *args)
37
+ end
38
+ end
39
+
40
+ def respond_to_missing?(name, include_all = false)
41
+ super || @color.respond_to?(name, include_all)
42
+ end
43
+ end # Delegator
44
+ end # Pastel
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+
3
+ module Pastel
4
+ VERSION = "0.1.0"
5
+ end
data/pastel.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pastel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pastel"
8
+ spec.version = Pastel::VERSION
9
+ spec.authors = ["Piotr Murach"]
10
+ spec.email = [""]
11
+ spec.summary = %q{Terminal strings styling with intuitive and clean API.}
12
+ spec.description = %q{Terminal strings styling with intuitive and clean API.}
13
+ spec.homepage = "https://github.com/peter-murach/pastel"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "equatable", "~> 0.5"
23
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pastel'
4
+
5
+ RSpec.configure do |config|
6
+ config.expect_with :rspec do |expectations|
7
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
8
+ end
9
+
10
+ config.mock_with :rspec do |mocks|
11
+ mocks.verify_partial_doubles = true
12
+ end
13
+
14
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
15
+ config.disable_monkey_patching!
16
+
17
+ # This setting enables warnings. It's recommended, but in some cases may
18
+ # be too noisy due to issues in dependencies.
19
+ config.warnings = true
20
+
21
+ if config.files_to_run.one?
22
+ config.default_formatter = 'doc'
23
+ end
24
+
25
+ config.profile_examples = 2
26
+
27
+ config.order = :random
28
+
29
+ Kernel.srand config.seed
30
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::Color, '.code' do
6
+ let(:string) { "This is a \e[1m\e[34mbold blue text\e[0m" }
7
+
8
+ subject(:color) { described_class.new }
9
+
10
+ it 'finds single code' do
11
+ expect(color.code(:black)).to eq(["\e[30m"])
12
+ end
13
+
14
+ it 'finds more than one code' do
15
+ expect(color.code(:black, :green)).to eq(["\e[30m", "\e[32m"])
16
+ end
17
+
18
+ it "doesn't find code" do
19
+ expect { color.code(:unkown) }.to raise_error(ArgumentError)
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::Color, '.decorate' do
6
+ let(:string) { 'string' }
7
+
8
+ subject(:color) { described_class.new }
9
+
10
+ it "doesn't apply styling to empty string" do
11
+ expect(color.decorate('')).to eq('')
12
+ end
13
+
14
+ it 'applies green text to string' do
15
+ expect(color.decorate(string, :green)).to eq("\e[32m#{string}\e[0m")
16
+ end
17
+
18
+ it 'applies red text background to string' do
19
+ expect(color.decorate(string, :on_red)).to eq("\e[41m#{string}\e[0m")
20
+ end
21
+
22
+ it 'applies style and color to string' do
23
+ expect(color.decorate(string, :bold, :green)).to eq("\e[1m\e[32m#{string}\e[0m")
24
+ end
25
+
26
+ it 'applies style, color and background to string' do
27
+ text = color.decorate(string, :bold, :green, :on_blue)
28
+ expect(text).to eq("\e[1m\e[32m\e[44m#{string}\e[0m")
29
+ end
30
+
31
+ it "applies styles to nested text" do
32
+ decorated = color.decorate(string + color.decorate(string, :red) + string, :green)
33
+ expect(decorated).to eq("\e[32m#{string}\e[31m#{string}\e[32m#{string}\e[0m")
34
+ end
35
+
36
+ it 'errors for unknown color' do
37
+ expect {
38
+ color.decorate(string, :crimson)
39
+ }.to raise_error(Pastel::InvalidAttributeNameError)
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::Color, '.strip' do
6
+ let(:instance) { described_class.new }
7
+
8
+ subject(:color) { instance.strip(string) }
9
+
10
+ context 'with ansi colors' do
11
+ let(:string) { "This is a \e[1m\e[34mbold blue text\e[0m" }
12
+
13
+ it 'removes color from string' do
14
+ is_expected.to eq('This is a bold blue text')
15
+ end
16
+ end
17
+
18
+ context 'with octal in encapsulating brackets' do
19
+ let(:string) { "\[\033[01;32m\]u@h \[\033[01;34m\]W $ \[\033[00m\]" }
20
+
21
+ it { is_expected.to eq('u@h W $ ') }
22
+ end
23
+
24
+ context 'with octal without brackets' do
25
+ let(:string) { "\033[01;32mu@h \033[01;34mW $ \033[00m" }
26
+
27
+ it { is_expected.to eq('u@h W $ ') }
28
+ end
29
+
30
+ context 'with octal with multiple colors' do
31
+ let(:string) { "\e[3;0;0;t\e[8;50;0t" }
32
+
33
+ it { is_expected.to eq('') }
34
+ end
35
+
36
+ context 'with control codes' do
37
+ let(:string ) { "WARN. \x1b[1m&\x1b[0m ERR. \x1b[7m&\x1b[0m" }
38
+
39
+ it { is_expected.to eq('WARN. & ERR. &') }
40
+ end
41
+
42
+ context 'with escape byte' do
43
+ let(:string) { "This is a \e[1m\e[34mbold blue text\e[0m" }
44
+
45
+ it { is_expected.to eq("This is a bold blue text") }
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::Color do
6
+
7
+ subject(:color) { described_class.new }
8
+
9
+ it "exposes all available style ANSI codes" do
10
+ expect(color.styles[:red]).to eq("\e[31m")
11
+ end
12
+ end
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::DecoratorChain do
6
+ it "is enumerable" do
7
+ expect(described_class.new).to be_a(Enumerable)
8
+ end
9
+
10
+ it "is equatable" do
11
+ expect(described_class.new).to be_a(Equatable)
12
+ end
13
+
14
+ describe ".each" do
15
+ it "yields each decorator" do
16
+ first = double('first')
17
+ second = double('second')
18
+ chain = described_class.new.add(first).add(second)
19
+ yielded = []
20
+
21
+ expect {
22
+ chain.each { |decorator| yielded << decorator }
23
+ }.to change { yielded }.from([]).to([first, second])
24
+ end
25
+ end
26
+
27
+ describe ".==" do
28
+ it "is equivalent with the same decorator" do
29
+ expect(described_class.new.add(:foo).add(:bar)).
30
+ to eq(described_class.new.add(:foo).add(:bar))
31
+ end
32
+
33
+ it "is not equivalent with different decorator" do
34
+ expect(described_class.new.add(:foo).add(:bar)).
35
+ not_to eq(described_class.new.add(:foo).add(:baz))
36
+ end
37
+
38
+ it "is not equivalent to another type" do
39
+ expect(described_class.new.add(:foo).add(:bar)).
40
+ not_to eq(:other)
41
+ end
42
+ end
43
+
44
+ describe ".inspect" do
45
+ it "displays object information" do
46
+ expect(described_class.new.inspect).to match(/decorators=\[\]/)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel::Delegator do
6
+ describe ".respond_to_missing?" do
7
+ context 'for a method defined on' do
8
+ it "returns true" do
9
+ chain = double(:chain)
10
+ decorator = described_class.new(chain)
11
+ expect(decorator.method(:styles)).not_to be_nil
12
+ end
13
+ end
14
+
15
+ context "for an undefined method " do
16
+ it "returns false" do
17
+ chain = double(:chain)
18
+ decorator = described_class.new(chain)
19
+ expect { decorator.method(:unknown) }.to raise_error(NameError)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,61 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pastel do
6
+
7
+ subject(:pastel) { described_class.new }
8
+
9
+ describe 'coloring string' do
10
+ it "doesn't apply styles to empty string" do
11
+ expect(pastel.red('')).to eq('')
12
+ end
13
+
14
+ it "colors string" do
15
+ expect(pastel.red("unicorn")).to eq("\e[31municorn\e[0m")
16
+ end
17
+
18
+ it "allows to specify variable number of arguments" do
19
+ expect(pastel.red("unicorn", "running")).to eq("\e[31municornrunning\e[0m")
20
+ end
21
+
22
+ it "combines colored strings with regular ones" do
23
+ expect(pastel.red("Unicorns") + ' will rule ' + pastel.green('the World!')).
24
+ to eq("\e[31mUnicorns\e[0m will rule \e[32mthe World!\e[0m")
25
+ end
26
+
27
+ it "composes color strings" do
28
+ expect(pastel.red.on_green.underline("unicorn")).
29
+ to eq("\e[4m\e[42m\e[31municorn\e[0m")
30
+ end
31
+
32
+ it "allows to nest mixed styles" do
33
+ expect(pastel.red("Unicorn" + pastel.green.on_yellow.underline('running') + '!')).
34
+ to eq("\e[31mUnicorn\e[4m\e[43m\e[32mrunning\e[31m!\e[0m")
35
+ end
36
+
37
+ it "allows for deep nesting" do
38
+ expect(pastel.red('r' + pastel.green('g' + pastel.yellow('y') + 'g') + 'r')).
39
+ to eq("\e[31mr\e[32mg\e[33my\e[32mg\e[31mr\e[0m")
40
+ end
41
+
42
+ it "allows for variable nested arguments" do
43
+ expect(pastel.red('r', pastel.green('g'), 'r')).
44
+ to eq("\e[31mr\e[32mg\e[31mr\e[0m")
45
+ end
46
+ end
47
+
48
+ describe '.valid?' do
49
+ it "when valid returns true" do
50
+ expect(pastel.valid?(:red)).to eq(true)
51
+ end
52
+
53
+ it "returns false when invalid" do
54
+ expect(pastel.valid?(:unknown)).to eq(false)
55
+ end
56
+ end
57
+
58
+ it "respond to styles method" do
59
+ expect(pastel).to respond_to(:styles)
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ desc 'Load gem inside irb console'
4
+ task :console do
5
+ require 'irb'
6
+ require 'irb/completion'
7
+ require File.join(__FILE__, '../../lib/pastel')
8
+ ARGV.clear
9
+ IRB.start
10
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ desc 'Measure code coverage'
4
+ task :coverage do
5
+ begin
6
+ original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
7
+ Rake::Task['spec'].invoke
8
+ ensure
9
+ ENV['COVERAGE'] = original
10
+ end
11
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Run all specs'
7
+ RSpec::Core::RakeTask.new(:spec) do |task|
8
+ task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
9
+ end
10
+
11
+ namespace :spec do
12
+ desc 'Run unit specs'
13
+ RSpec::Core::RakeTask.new(:unit) do |task|
14
+ task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
15
+ end
16
+
17
+ desc 'Run integration specs'
18
+ RSpec::Core::RakeTask.new(:integration) do |task|
19
+ task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
20
+ end
21
+ end
22
+
23
+ rescue LoadError
24
+ %w[spec spec:unit spec:integration].each do |name|
25
+ task name do
26
+ $stderr.puts "In order to run #{name}, do `gem install rspec`"
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pastel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Murach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: equatable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ description: Terminal strings styling with intuitive and clean API.
42
+ email:
43
+ - ''
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - .ruby-gemset
51
+ - .ruby-version
52
+ - .travis.yml
53
+ - Gemfile
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - lib/pastel.rb
58
+ - lib/pastel/ansi.rb
59
+ - lib/pastel/color.rb
60
+ - lib/pastel/color_resolver.rb
61
+ - lib/pastel/decorator_chain.rb
62
+ - lib/pastel/delegator.rb
63
+ - lib/pastel/version.rb
64
+ - pastel.gemspec
65
+ - spec/spec_helper.rb
66
+ - spec/unit/color/code_spec.rb
67
+ - spec/unit/color/decorate_spec.rb
68
+ - spec/unit/color/strip_spec.rb
69
+ - spec/unit/color/styles_spec.rb
70
+ - spec/unit/decorator_chain_spec.rb
71
+ - spec/unit/delegator_spec.rb
72
+ - spec/unit/new_spec.rb
73
+ - tasks/console.rake
74
+ - tasks/coverage.rake
75
+ - tasks/spec.rake
76
+ homepage: https://github.com/peter-murach/pastel
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.0.3
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Terminal strings styling with intuitive and clean API.
100
+ test_files:
101
+ - spec/spec_helper.rb
102
+ - spec/unit/color/code_spec.rb
103
+ - spec/unit/color/decorate_spec.rb
104
+ - spec/unit/color/strip_spec.rb
105
+ - spec/unit/color/styles_spec.rb
106
+ - spec/unit/decorator_chain_spec.rb
107
+ - spec/unit/delegator_spec.rb
108
+ - spec/unit/new_spec.rb
109
+ has_rdoc: