pastel-0.7.3/0000755000175000017500000000000013611565237012400 5ustar boutilboutilpastel-0.7.3/tasks/0000755000175000017500000000000013611565237013525 5ustar boutilboutilpastel-0.7.3/tasks/spec.rake0000644000175000017500000000125513611565237015326 0ustar boutilboutil# encoding: utf-8 begin require 'rspec/core/rake_task' desc 'Run all specs' RSpec::Core::RakeTask.new(:spec) do |task| task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb' end namespace :spec do desc 'Run unit specs' RSpec::Core::RakeTask.new(:unit) do |task| task.pattern = 'spec/unit{,/*/**}/*_spec.rb' end desc 'Run integration specs' RSpec::Core::RakeTask.new(:integration) do |task| task.pattern = 'spec/integration{,/*/**}/*_spec.rb' end end rescue LoadError %w[spec spec:unit spec:integration].each do |name| task name do $stderr.puts "In order to run #{name}, do `gem install rspec`" end end end pastel-0.7.3/tasks/coverage.rake0000644000175000017500000000032213611565237016161 0ustar boutilboutil# encoding: utf-8 desc 'Measure code coverage' task :coverage do begin original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true' Rake::Task['spec'].invoke ensure ENV['COVERAGE'] = original end end pastel-0.7.3/tasks/console.rake0000644000175000017500000000032213611565237016030 0ustar boutilboutil# encoding: utf-8 desc 'Load gem inside irb console' task :console do require 'irb' require 'irb/completion' require File.join(__FILE__, '../../lib/pastel') ARGV.clear IRB.start end task c: :console pastel-0.7.3/spec/0000755000175000017500000000000013611565237013332 5ustar boutilboutilpastel-0.7.3/spec/unit/0000755000175000017500000000000013611565237014311 5ustar boutilboutilpastel-0.7.3/spec/unit/undecorate_spec.rb0000644000175000017500000000052413611565237020002 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel, '#undecorate' do subject(:pastel) { described_class.new(enabled: true) } it "undecorates string detecting color escape codes" do string = pastel.red.on_green('foo') expect(pastel.undecorate(string)).to eq([ {foreground: :red, background: :on_green, text: 'foo'} ]) end end pastel-0.7.3/spec/unit/respond_to_spec.rb0000644000175000017500000000066413611565237020032 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel, '.respond_to?' do subject(:pastel) { described_class.new(enabled: true) } it "responds correctly to color method" do expect(pastel.respond_to?(:decorate)).to eq(true) end it "responds correctly to color property" do expect(pastel.respond_to?(:red)).to eq(true) end it "responds correctly to unkown method" do expect(pastel.respond_to?(:unknown)).to eq(false) end end pastel-0.7.3/spec/unit/new_spec.rb0000644000175000017500000000326513611565237016447 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel, '#new' do subject(:pastel) { described_class.new(enabled: true) } it { is_expected.to respond_to(:lookup) } it { is_expected.to respond_to(:decorate) } it { is_expected.to respond_to(:undecorate) } it { is_expected.to respond_to(:strip) } describe '#valid?' do it "when valid returns true" do expect(pastel.valid?(:red)).to eq(true) end it "returns false when invalid" do expect(pastel.valid?(:unknown)).to eq(false) end end describe '#colored?' do it "checks if string is colored" do expect(pastel.colored?("\e[31mfoo\e[0m")).to eq(true) end end describe 'options passed in' do it 'defaults enabled to color detection' do allow(TTY::Color).to receive(:color?).and_return(true) allow(TTY::Color).to receive(:windows?).and_return(false) pastel = described_class.new expect(pastel.enabled?).to eq(true) expect(TTY::Color).to have_received(:color?) end it "defaults to enabled on Windows" do allow(TTY::Color).to receive(:color?).and_return(false) allow(TTY::Color).to receive(:windows?).and_return(true) pastel = described_class.new expect(pastel.enabled?).to eq(true) expect(TTY::Color).to_not have_received(:color?) end it "sets enabled option" do pastel = described_class.new(enabled: false) expect(pastel.enabled?).to eq(false) expect(pastel.red('Unicorn', pastel.green('!'))).to eq('Unicorn!') end it "sets eachline option" do pastel = described_class.new(enabled: true, eachline: "\n") expect(pastel.red("foo\nbar")).to eq("\e[31mfoo\e[0m\n\e[31mbar\e[0m") end end end pastel-0.7.3/spec/unit/detach_spec.rb0000644000175000017500000000243613611565237017105 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel, '.detach' do subject(:pastel) { described_class.new(enabled: true) } it "creates detached instance" do error = pastel.red.bold.detach expect(error).to be_a(Pastel::Detached) end it "ensures instance is immutable" do error = pastel.red.detach expect(error.frozen?).to be(true) end it "detaches colors combination" do error = pastel.red.bold.detach expect(error.call('unicorn')).to eq("\e[31;1municorn\e[0m") expect(error.call('error')).to eq("\e[31;1merror\e[0m") end it "allows array like access" do error = pastel.red.bold.detach expect(error['unicorn']).to eq("\e[31;1municorn\e[0m") end it "allows alternative call invocation" do error = pastel.red.bold.detach expect(error.('unicorn')).to eq("\e[31;1municorn\e[0m") end it "calls detached colors with no arguments" do warning = pastel.yellow.detach expect(warning.call('')).to eq('') end it "inspects detached colors" do warning = pastel.yellow.bold.detach expect(warning.inspect).to eq('#') end it "accepts multiple strings" do error = pastel.red.bold.detach expect(error.call('Unicorns', ' run ', 'wild')). to eq("\e[31;1mUnicorns run wild\e[0m") end end pastel-0.7.3/spec/unit/delegator_spec.rb0000644000175000017500000000220213611565237017612 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel::Delegator do it "returns delegator for color without argument" do pastel = Pastel.new(enabled: true) expect(pastel.red).to be_a(Pastel::Delegator) end describe ".inspect" do it "inspects delegator styles chain" do chain = ['red', 'on_green'] delegator = described_class.new(:resolver, chain) allow(delegator).to receive(:styles).and_return({red: 31, on_green: 42}) expect(delegator.inspect).to eq("#") end end describe ".respond_to_missing?" do context 'for a method defined on' do it "returns true" do resolver = double(:resolver) chain = double(:chain) decorator = described_class.new(resolver, chain) expect(decorator.method(:styles)).not_to be_nil end end context "for an undefined method " do it "returns false" do resolver = double(:resolver, color: true) chain = double(:chain) decorator = described_class.new(resolver, chain) expect { decorator.method(:unknown) }.to raise_error(NameError) end end end end pastel-0.7.3/spec/unit/decorator_chain_spec.rb0000644000175000017500000000231513611565237020775 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel::DecoratorChain do it "is enumerable" do expect(described_class.new).to be_a(Enumerable) end it "is equatable" do expect(described_class.new).to be_a(Equatable) end describe ".each" do it "yields each decorator" do first = double('first') second = double('second') chain = described_class.new.add(first).add(second) yielded = [] expect { chain.each { |decorator| yielded << decorator } }.to change { yielded }.from([]).to([first, second]) end end describe ".==" do it "is equivalent with the same decorator" do expect(described_class.new.add(:foo).add(:bar)). to eq(described_class.new.add(:foo).add(:bar)) end it "is not equivalent with different decorator" do expect(described_class.new.add(:foo).add(:bar)). not_to eq(described_class.new.add(:foo).add(:baz)) end it "is not equivalent to another type" do expect(described_class.new.add(:foo).add(:bar)). not_to eq(:other) end end describe ".inspect" do it "displays object information" do expect(described_class.new.inspect).to match(/decorators=\[\]/) end end end pastel-0.7.3/spec/unit/decorate_dsl_spec.rb0000644000175000017500000000564613611565237020313 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel, 'coloring dsl' do subject(:pastel) { described_class.new(enabled: true) } it "colors string" do expect(pastel.red("unicorn")).to eq("\e[31municorn\e[0m") end it "allows to specify variable number of arguments" do expect(pastel.red("unicorn", "running")).to eq("\e[31municornrunning\e[0m") end it "combines colored strings with regular ones" do expect(pastel.red("Unicorns") + ' will rule ' + pastel.green('the World!')). to eq("\e[31mUnicorns\e[0m will rule \e[32mthe World!\e[0m") end it "composes two color strings " do expect(pastel.red.on_green("unicorn")).to eq("\e[31;42municorn\e[0m") end it "composes three color strings" do expect(pastel.red.on_green.underline("unicorn")). to eq("\e[31;42;4municorn\e[0m") end it "combines colored composed strings with regular ones" do expect(pastel.red.on_green("Unicorns") + ' will rule ' + pastel.green.on_red('the World!')). to eq("\e[31;42mUnicorns\e[0m will rule \e[32;41mthe World!\e[0m") end it "allows one level nesting" do expect(pastel.red("Unicorn" + pastel.blue("rule!"))). to eq("\e[31mUnicorn\e[34mrule!\e[0m\e[0m") end it "allows to nest mixed styles" do expect(pastel.red("Unicorn" + pastel.green.on_yellow.underline('running') + '!')). to eq("\e[31mUnicorn\e[32;43;4mrunning\e[0m\e[31m!\e[0m") end it "allows for deep nesting" do expect(pastel.red('r' + pastel.green('g' + pastel.yellow('y') + 'g') + 'r')). to eq("\e[31mr\e[32mg\e[33my\e[0m\e[32mg\e[0m\e[31mr\e[0m") end it "allows for variable nested arguments" do expect(pastel.red('r', pastel.green('g'), 'r')). to eq("\e[31mr\e[32mg\e[0m\e[31mr\e[0m") end it "nests color foreground & background" do expect(pastel.on_red('foo', pastel.green('bar'), 'foo')). to eq("\e[41mfoo\e[32mbar\e[0m\e[41mfoo\e[0m") end it "allows to nest styles within block" do string = pastel.red.on_green('Unicorns' + pastel.green.on_red('will ', 'dominate' + pastel.yellow('the world!'))) expect(pastel.red.on_green('Unicorns') do green.on_red('will ', 'dominate') do yellow('the world!') end end).to eq(string) end it "doesn't decorate nil" do expect(pastel.red(nil)).to eq('') end it "doesn't apply styles to empty string" do expect(pastel.red('')).to eq('') end it "applies styles to empty with width more than 1" do expect(pastel.red(' ')).to eq("\e[31m \e[0m") end it "applies color only once" do expect(pastel.red.red.red("unicorn")).to eq(pastel.red("unicorn")) end it "raises error when chained with unrecognized color" do expect { pastel.unknown.on_red('unicorn') }.to raise_error(Pastel::InvalidAttributeNameError) end it "raises error when doesn't recognize color" do expect { pastel.unknown('unicorn') }.to raise_error(Pastel::InvalidAttributeNameError) end end pastel-0.7.3/spec/unit/color_parser_spec.rb0000644000175000017500000000333613611565237020347 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::ColorParser, '::parse' do subject(:parser) { described_class } it "parses string with no color" do expect(parser.parse("foo")).to eq([{text: 'foo'}]) end it "parses simple color" do expect(parser.parse("\e[32mfoo\e[0m")).to eq([ {foreground: :green, text: 'foo'} ]) end it "parses simple color and style" do expect(parser.parse("\e[32;1mfoo\e[0m")).to eq([ {foreground: :green, style: :bold, text: 'foo'} ]) end it "parses chained colors in shorthand syntax" do expect(parser.parse("\e[32;44mfoo\e[0m")).to eq([ {foreground: :green, background: :on_blue, text: 'foo'} ]) end it "parses chained colors in regular syntax" do expect(parser.parse("\e[32m\e[44mfoo\e[0m")).to eq([ {foreground: :green, background: :on_blue, text: 'foo'} ]) end it "parses many colors" do expect(parser.parse("\e[32mfoo\e[0m \e[31mbar\e[0m")).to eq([ {foreground: :green, text: 'foo'}, {text: ' '}, {foreground: :red, text: 'bar'} ]) end it "parses nested colors with one reset" do expect(parser.parse("\e[32mfoo\e[31mbar\e[0m")).to eq([ {foreground: :green, text: 'foo'}, {foreground: :red, text: 'bar'} ]) end it "parses nested colors with two resets" do expect(parser.parse("\e[32mfoo\e[31mbar\e[0m\e[0m")).to eq([ {foreground: :green, text: 'foo'}, {foreground: :red, text: 'bar'} ]) end it "parses unrest color" do expect(parser.parse("\e[32mfoo")).to eq([ {foreground: :green, text: 'foo'} ]) end it "parses malformed control sequence" do expect(parser.parse("\eA foo bar ESC\e")).to eq([ {text: "\eA foo bar ESC\e"} ]) end end pastel-0.7.3/spec/unit/color/0000755000175000017500000000000013611565237015427 5ustar boutilboutilpastel-0.7.3/spec/unit/color/valid_spec.rb0000644000175000017500000000073713611565237020074 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '.valid?' do it "detects valid colors" do color = described_class.new expect(color.valid?(:red, :on_green, :bold)).to eq(true) end it "detects valid color aliases" do color = described_class.new color.alias_color(:funky, :red) expect(color.valid?(:funky)).to eq(true) end it "detects invalid color" do color = described_class.new expect(color.valid?(:red, :unknown)).to eq(false) end end pastel-0.7.3/spec/unit/color/styles_spec.rb0000644000175000017500000000033313611565237020310 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel::Color, '#styles' do subject(:color) { described_class.new(enabled: true) } it "exposes all available style ANSI codes" do expect(color.styles[:red]).to eq(31) end end pastel-0.7.3/spec/unit/color/strip_spec.rb0000644000175000017500000000315013611565237020126 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '.strip' do subject(:color) { described_class.new(enabled: true) } it 'strips ansi color from string' do string = "This is a \e[1m\e[34mbold blue text\e[0m" expect(color.strip(string)).to eq('This is a bold blue text') end it "strips partial ansi color" do string = "foo\e[1mbar" expect(color.strip(string)).to eq('foobar') end it 'preserves movement characters' do # [176A - move cursor up n lines expect(color.strip("foo\e[176Abar")).to eq("foo\e[176Abar") end it 'strips reset/setfg/setbg/italics/strike/underline sequence' do string = "\x1b[0;33;49;3;9;4mfoo\x1b[0m" expect(color.strip(string)).to eq("foo") end it 'strips octal in encapsulating brackets' do string = "\[\033[01;32m\]u@h \[\033[01;34m\]W $ \[\033[00m\]" expect(color.strip(string)).to eq('[]u@h []W $ []') end it 'strips octal codes without brackets' do string = "\033[01;32mu@h \033[01;34mW $ \033[00m" expect(color.strip(string)).to eq('u@h W $ ') end it 'strips octal with multiple colors' do string = "\e[3;0;0;mfoo\e[8;50;0m" expect(color.strip(string)).to eq('foo') end it "strips multiple colors delimited by :" do string = "\e[31:44:4mfoo\e[0m" expect(color.strip(string)).to eq('foo') end it 'strips control codes' do string = "WARN. \x1b[1m&\x1b[0m ERR. \x1b[7m&\x1b[0m" expect(color.strip(string)).to eq('WARN. & ERR. &') end it 'strips escape bytes' do string = "This is a \e[1m\e[34mbold blue text\e[0m" expect(color.strip(string)).to eq("This is a bold blue text") end end pastel-0.7.3/spec/unit/color/new_spec.rb0000644000175000017500000000040113611565237017552 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '::new' do it "allows to disable coloring" do color = described_class.new(enabled: false) expect(color.enabled?).to eq(false) expect(color.decorate("Unicorn", :red)).to eq("Unicorn") end end pastel-0.7.3/spec/unit/color/lookup_spec.rb0000644000175000017500000000076413611565237020306 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '#lookup' do it "looksup colors" do color = described_class.new(enabled: true) expect(color.lookup(:red, :on_green, :bold)).to eq("\e[31;42;1m") end it "caches color lookups" do color = described_class.new(enabled: true) allow(color).to receive(:code).and_return([31]) color.lookup(:red, :on_green) color.lookup(:red, :on_green) color.lookup(:red, :on_green) expect(color).to have_received(:code).once end end pastel-0.7.3/spec/unit/color/equal_spec.rb0000644000175000017500000000134613611565237020101 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '#==' do it "is true with the same enabled and eachline attributes" do expect(Pastel::Color.new(enabled: false, eachline: "\n")). to eq(Pastel::Color.new(enabled: false, eachline: "\n")) end it "is false with different enabled attribute" do expect(Pastel::Color.new(enabled: true, eachline: "\n")). not_to eq(Pastel::Color.new(enabled: false, eachline: "\n")) end it "is false with different eachline attribute" do expect(Pastel::Color.new(enabled: false, eachline: "\n")). not_to eq(Pastel::Color.new(enabled: false, eachline: "\r\n")) end it "is false with non-color" do expect(Pastel::Color.new(enabled: true)).not_to eq(:other) end end pastel-0.7.3/spec/unit/color/decorate_spec.rb0000644000175000017500000000436413611565237020563 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '.decorate' do let(:string) { 'string' } subject(:color) { described_class.new(enabled: true) } it "doesn't output styling when disabled" do color = described_class.new(enabled: false) expect(color.decorate('foo', :red)).to eq('foo') end it "doesn't apply styling to empty string" do expect(color.decorate('')).to eq('') end it "doesn't decorate without color" do expect(color.decorate(string)).to eq(string) end it 'applies green text to string' do expect(color.decorate(string, :green)).to eq("\e[32m#{string}\e[0m") end it 'applies red text background to string' do expect(color.decorate(string, :on_red)).to eq("\e[41m#{string}\e[0m") end it 'applies style and color to string' do expect(color.decorate(string, :bold, :green)).to eq("\e[1;32m#{string}\e[0m") end it 'applies style, color and background to string' do text = color.decorate(string, :bold, :green, :on_blue) expect(text).to eq("\e[1;32;44m#{string}\e[0m") end it "applies styles to nested text" do decorated = color.decorate(string + color.decorate(string, :red) + string, :green) expect(decorated).to eq("\e[32m#{string}\e[31m#{string}\e[0m\e[32m#{string}\e[0m") end it "decorates multiline string as regular by default" do string = "foo\nbar\nbaz" expect(color.decorate(string, :red)).to eq("\e[31mfoo\nbar\nbaz\e[0m") end it "allows to decorate each line separately" do string = "foo\nbar\nbaz" color = described_class.new(enabled: true, eachline: "\n") expect(color.decorate(string, :red)).to eq([ "\e[31mfoo\e[0m", "\e[31mbar\e[0m", "\e[31mbaz\e[0m" ].join("\n")) end it 'errors for unknown color' do expect { color.decorate(string, :crimson) }.to raise_error(Pastel::InvalidAttributeNameError) end it "doesn't decorate non-string instance" do expect(color.decorate({}, :red)).to eq({}) end it "doesn't decorate nil" do expect(color.decorate(nil, :red)).to eq(nil) end it "doesn't decorate zero length string" do expect(color.decorate('', :red)).to eq('') end it "doesn't decorate non-zero length string" do expect(color.decorate(' ', :red)).to eq("\e[31m \e[0m") end end pastel-0.7.3/spec/unit/color/colored_spec.rb0000644000175000017500000000060713611565237020420 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '#colored?' do subject(:color) { described_class.new(enabled: true) } it "checks if string has color codes" do string = "foo\e[31mbar\e[0m" expect(color.colored?(string)).to eq(true) end it "checks that string doesn't contain color codes" do string = "foo\nbar" expect(color.colored?(string)).to eq(false) end end pastel-0.7.3/spec/unit/color/code_spec.rb0000644000175000017500000000114513611565237017701 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '#code' do let(:string) { "This is a \e[1m\e[34mbold blue text\e[0m" } subject(:color) { described_class.new(enabled: true) } it 'finds single code' do expect(color.code(:black)).to eq([30]) end it 'finds more than one code' do expect(color.code(:black, :green)).to eq([30, 32]) end it "doesn't find code" do expect { color.code(:unkown) }.to raise_error(ArgumentError) end it "finds alias code" do color.alias_color(:funky, :red, :bold) expect(color.code(:funky)).to eq([color.code(:red) + color.code(:bold)]) end end pastel-0.7.3/spec/unit/color/alias_color_spec.rb0000644000175000017500000000222113611565237021252 0ustar boutilboutil# encoding: utf-8 RSpec.describe Pastel::Color, '.alias_color' do subject(:color) { described_class.new(enabled: true) } it 'aliases non existent color' do expect { color.alias_color(:funky, :unknown) }.to raise_error(Pastel::InvalidAttributeNameError) end it 'aliases color with invalid name' do expect { color.alias_color('some name', :red) }.to raise_error(Pastel::InvalidAliasNameError, /Invalid alias name/) end it 'aliases standard color' do expect { color.alias_color(:red, :red) }.to raise_error(Pastel::InvalidAliasNameError, /alias standard color/) end it 'aliases color :red to :funky' do color.alias_color(:funky, :red, :bold) expect(color.valid?(:funky)).to eq(true) expect(color.code(:funky)).to eq([[31, 1]]) expect(color.lookup(:funky)).to eq("\e[31;1m") end it "has global aliases" do color_foo = described_class.new(enabled: true) color_bar = described_class.new(enabled: true) color_foo.alias_color(:foo, :red) color_bar.alias_color(:bar, :red) expect(color_foo.valid?(:foo)).to eq(true) expect(color_foo.valid?(:bar)).to eq(true) end end pastel-0.7.3/spec/unit/alias_importer_spec.rb0000644000175000017500000000165213611565237020666 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel::AliasImporter, '#import' do let(:color) { spy(:color, alias_color: true) } let(:output) { StringIO.new } it "imports aliases from environment" do color_aliases = "funky=red.bold,base=bright_yellow" env = {'PASTEL_COLORS_ALIASES' => color_aliases} importer = described_class.new(color, env) importer.import expect(color).to have_received(:alias_color).with(:funky, :red, :bold) expect(color).to have_received(:alias_color).with(:base, :bright_yellow) end it "fails to import incorrectly formatted colors" do color_aliases = "funky red,base=bright_yellow" env = {'PASTEL_COLORS_ALIASES' => color_aliases} importer = described_class.new(color, env, output) output.rewind importer.import expect(output.string).to eq("Bad color mapping `funky red`\n") expect(color).to have_received(:alias_color).with(:base, :bright_yellow) end end pastel-0.7.3/spec/unit/alias_color_spec.rb0000644000175000017500000000130513611565237020136 0ustar boutilboutil# coding: utf-8 RSpec.describe Pastel, '#alias_color' do subject(:pastel) { described_class.new(enabled: true) } it "aliases color" do pastel.alias_color(:funky, :red, :bold) expect(pastel.funky('unicorn')).to eq("\e[31;1municorn\e[0m") end it "aliases color and combines with regular ones" do pastel.alias_color(:funky, :red, :bold) expect(pastel.funky.on_green('unicorn')).to eq("\e[31;1;42municorn\e[0m") end it "reads aliases from the environment" do color_aliases = "funky=red" allow(ENV).to receive(:[]).with('PASTEL_COLORS_ALIASES'). and_return(color_aliases) described_class.new(enabled: true) expect(pastel.valid?(:funky)).to eq(true) end end pastel-0.7.3/spec/spec_helper.rb0000644000175000017500000000202113611565237016143 0ustar boutilboutil# encoding: utf-8 if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS']) require 'simplecov' require 'coveralls' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter ] SimpleCov.start do command_name 'spec' add_filter 'spec' end end require 'pastel' RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end # Limits the available syntax to the non-monkey patched syntax that is recommended. config.disable_monkey_patching! # This setting enables warnings. It's recommended, but in some cases may # be too noisy due to issues in dependencies. config.warnings = true if config.files_to_run.one? config.default_formatter = 'doc' end config.profile_examples = 2 config.order = :random Kernel.srand config.seed end pastel-0.7.3/pastel.gemspec0000644000175000017500000000315013611565237015234 0ustar boutilboutillib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'pastel/version' Gem::Specification.new do |spec| spec.name = "pastel" spec.version = Pastel::VERSION spec.authors = ["Piotr Murach"] spec.email = ["me@piotrmurach.com"] spec.summary = %q{Terminal strings styling with intuitive and clean API.} spec.description = %q{Terminal strings styling with intuitive and clean API.} spec.homepage = "https://piotrmurach.github.io/tty/" spec.license = "MIT" if spec.respond_to?(:metadata=) spec.metadata = { "allowed_push_host" => "https://rubygems.org", "bug_tracker_uri" => "https://github.com/piotrmurach/pastel/issues", "changelog_uri" => "https://github.com/piotrmurach/pastel/blob/master/CHANGELOG.md", "documentation_uri" => "https://www.rubydoc.info/gems/pastel", "homepage_uri" => spec.homepage, "source_code_uri" => "https://github.com/piotrmurach/pastel" } end spec.files = Dir['{lib,spec,examples}/**/*.rb'] spec.files += Dir['tasks/*', 'pastel.gemspec'] spec.files += Dir['README.md', 'CHANGELOG.md', 'LICENSE.txt', 'Rakefile'] spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^spec/}) spec.require_paths = ["lib"] spec.add_dependency 'equatable', '~> 0.6' spec.add_dependency 'tty-color', '~> 0.5' spec.add_development_dependency 'bundler', '>= 1.5.0' spec.add_development_dependency 'rspec', '~> 3.1' spec.add_development_dependency 'rake' end pastel-0.7.3/lib/0000755000175000017500000000000013611565237013146 5ustar boutilboutilpastel-0.7.3/lib/pastel/0000755000175000017500000000000013611565237014436 5ustar boutilboutilpastel-0.7.3/lib/pastel/version.rb0000644000175000017500000000006713611565237016453 0ustar boutilboutil# coding: utf-8 module Pastel VERSION = '0.7.3' end pastel-0.7.3/lib/pastel/detached.rb0000644000175000017500000000160113611565237016522 0ustar boutilboutil# encoding: utf-8 require 'equatable' module Pastel # A class representing detached color class Detached include Equatable # Initialize a detached object # # @param [Pastel::Color] color # the color instance # @param [Array[Symbol]] styles # the styles to be applied # # @api private def initialize(color, *styles) @color = color @styles = styles.dup freeze end # Decorate the values corresponding to styles # # @example # # @param [String] value # the stirng to decorate with styles # # @return [String] # # @api public def call(*args) value = args.join @color.decorate(value, *styles) end alias_method :[], :call # @api public def to_proc self end private # @api private attr_reader :styles end # Detached end # Pastel pastel-0.7.3/lib/pastel/delegator.rb0000644000175000017500000000373413611565237016740 0ustar boutilboutil# coding: utf-8 require 'equatable' require 'forwardable' require_relative 'color_parser' require_relative 'decorator_chain' module Pastel # Wrapes the {DecoratorChain} to allow for easy resolution # of string coloring. # # @api private class Delegator extend Forwardable include Equatable def_delegators '@resolver.color', :valid?, :styles, :strip, :decorate, :enabled?, :colored?, :alias_color, :lookup def_delegators ColorParser, :parse alias_method :undecorate, :parse # Create Delegator # # Used internally by {Pastel} # # @param [ColorResolver] resolver # # @param [DecoratorChain] base # # @api private def initialize(resolver, base) @resolver = resolver @base = base end # @api public def self.for(resolver, base) new(resolver, base) end remove_method :inspect # Object string representation # # @return [String] # # @api def inspect "#" end alias_method :to_s, :inspect protected attr_reader :base attr_reader :resolver # Wrap colors # # @api private def wrap(base) self.class.new(resolver, base) end def method_missing(method_name, *args, &block) new_base = base.add(method_name) delegator = wrap(new_base) if args.empty? && !(method_name.to_sym == :detach) delegator else string = args.join string << evaluate_block(&block) if block_given? resolver.resolve(new_base, string) end end def respond_to_missing?(name, include_all = false) resolver.color.respond_to?(name, include_all) || resolver.color.valid?(name) || super end # Evaluate color block # # @api private def evaluate_block(&block) delegator = self.class.new(resolver, DecoratorChain.empty) delegator.instance_eval(&block) end end # Delegator end # Pastel pastel-0.7.3/lib/pastel/decorator_chain.rb0000644000175000017500000000150313611565237020106 0ustar boutilboutil# coding: utf-8 require 'equatable' module Pastel # Collects a list of decorators for styling a string # # @api private class DecoratorChain include Enumerable include Equatable def initialize(decorators = []) @decorators = decorators end # Add decorator # # @api public def add(decorator) if decorators.include?(decorator) self.class.new(decorators) else self.class.new(decorators + [decorator]) end end # Iterate over list of decorators # # @api public def each(&block) decorators.each(&block) end # Create an empty decorator chain # # @return [DecoratorChain] # # @api public def self.empty new([]) end protected attr_reader :decorators end # DecoratorChain end # Patel pastel-0.7.3/lib/pastel/color_resolver.rb0000644000175000017500000000130713611565237020023 0ustar boutilboutil# coding: utf-8 require_relative 'detached' module Pastel # Contains logic for resolving styles applied to component # # Used internally by {Delegator}. # # @api private class ColorResolver # The color instance # @api public attr_reader :color # Initialize ColorResolver # # @param [Color] color # # @api private def initialize(color) @color = color end # Resolve uncolored string # # @api private def resolve(base, unprocessed_string) if base.to_a.last == :detach Detached.new(color, *base.to_a[0...-1]) else color.decorate(unprocessed_string, *base) end end end # ColorResolver end # Pastel pastel-0.7.3/lib/pastel/color_parser.rb0000644000175000017500000000554413611565237017465 0ustar boutilboutil# encoding: utf-8 require_relative 'ansi' module Pastel # Responsible for parsing color symbols out of text with color escapes # # Used internally by {Color}. # # @api private class ColorParser include ANSI ESC = "\x1b".freeze CSI = "\[".freeze # Parse color escape sequences into a list of hashes # corresponding to the color attributes being set by these # sequences # # @example # parse("\e[32mfoo\e[0m") # => [{colors: [:green], text: 'foo'} # # @param [String] text # the text to parse for presence of color ansi codes # # @return [Array[Hash[Symbol,String]]] # # @api public def self.parse(text) scanner = StringScanner.new(text) state = {} result = [] ansi_stack = [] text_chunk = '' until scanner.eos? char = scanner.getch # match control if char == ESC && (delim = scanner.getch) == CSI if scanner.scan(/^0m/) unpack_ansi(ansi_stack) { |attr, name| state[attr] = name } ansi_stack = [] elsif scanner.scan(/^([1-9;:]+)m/) # ansi codes separated by text if !text_chunk.empty? && !ansi_stack.empty? unpack_ansi(ansi_stack) { |attr, name| state[attr] = name } ansi_stack = [] end scanner[1].split(/:|;/).each do |code| ansi_stack << code end end if !text_chunk.empty? state[:text] = text_chunk result.push(state) state = {} text_chunk = '' end elsif char == ESC # broken escape text_chunk << char + delim.to_s else text_chunk << char end end if !text_chunk.empty? state[:text] = text_chunk end if !ansi_stack.empty? unpack_ansi(ansi_stack) { |attr, name| state[attr] = name} end if state.values.any? { |val| !val.empty? } result.push(state) end result end # Remove from current stack all ansi codes # # @param [Array[Integer]] ansi_stack # the stack with all the ansi codes # # @yield [Symbol, Symbol] attr, name # # @api private def self.unpack_ansi(ansi_stack) ansi_stack.each do |ansi| name = ansi_for(ansi) attr = attribute_for(ansi) yield attr, name end end # Decide attribute name for ansi # # @param [Integer] ansi # the ansi escape code # # @return [Symbol] # # @api private def self.attribute_for(ansi) if ANSI.foreground?(ansi) :foreground elsif ANSI.background?(ansi) :background elsif ANSI.style?(ansi) :style end end # @api private def self.ansi_for(ansi) ATTRIBUTES.key(ansi.to_i) end end # Parser end # Pastel pastel-0.7.3/lib/pastel/color.rb0000644000175000017500000001307213611565237016104 0ustar boutilboutil# encoding: utf-8 require 'equatable' require_relative 'ansi' module Pastel # A class responsible for coloring strings. class Color include Equatable include ANSI # All color aliases ALIASES = {} # Match all color escape sequences ANSI_COLOR_REGEXP = /\x1b+(\[|\[\[)[0-9;:?]+m/mo.freeze attr_reader :enabled alias_method :enabled?, :enabled attr_reader :eachline # Initialize a Terminal Color # # @api public def initialize(options = {}) @enabled = options[:enabled] @eachline = options.fetch(:eachline) { false } @cache = {} end # Disable coloring of this terminal session # # @api public def disable! @enabled = false end # Apply ANSI color to the given string. # # Wraps eachline with clear escape. # # @param [String] string # text to add ANSI strings # # @param [Array[Symbol]] colors # the color names # # @example # color.decorate "text", :yellow, :on_green, :underline # # @return [String] # the colored string # # @api public def decorate(string, *colors) return string if blank?(string) || !enabled || colors.empty? ansi_colors = lookup(*colors.dup.uniq) if eachline string.dup.split(eachline).map! do |line| apply_codes(line, ansi_colors) end.join(eachline) else apply_codes(string.dup, ansi_colors) end end # Apply escape codes to the string # # @param [String] string # the string to apply escapes to # @param [Strin] ansi_colors # the ansi colors to apply # # @return [String] # return the string surrounded by escape codes # # @api private def apply_codes(string, ansi_colors) "#{ansi_colors}#{string.gsub(/(\e\[0m)([^\e]+)$/, "\\1#{ansi_colors}\\2")}\e[0m" end # Reset sequence # # @api public def clear lookup(:clear) end # Strip ANSI color codes from a string. # # Only ANSI color codes are removed, not movement codes or # other escapes sequences are stripped. # # @param [Array[String]] strings # a string or array of strings to sanitize # # @example # strip("foo\e[1mbar\e[0m") # => "foobar" # # @return [String] # # @api public def strip(*strings) modified = strings.map { |string| string.dup.gsub(ANSI_COLOR_REGEXP, '') } modified.size == 1 ? modified[0] : modified end # Check if string has color escape codes # # @param [String] string # the string to check for color strings # # @return [Boolean] # true when string contains color codes, false otherwise # # @api public def colored?(string) !ANSI_COLOR_REGEXP.match(string).nil? end # Find the escape code for a given set of color attributes # # @example # color.lookup(:red, :on_green) # => "\e[31;42m" # # @param [Array[Symbol]] colors # the list of color name(s) to lookup # # @return [String] # the ANSI code(s) # # @raise [InvalidAttributeNameError] # exception raised for any invalid color name # # @api private def lookup(*colors) @cache.fetch(colors) do @cache[colors] = "\e[#{code(*colors).join(';')}m" end end # Return raw color code without embeding it into a string. # # @return [Array[String]] # ANSI escape codes # # @api public def code(*colors) attribute = [] colors.each do |color| value = ANSI::ATTRIBUTES[color] || ALIASES[color] if value attribute << value else validate(color) end end attribute end # Expose all ANSI color names and their codes # # @return [Hash[Symbol]] # # @api public def styles ANSI::ATTRIBUTES.merge(ALIASES) end # List all available style names # # @return [Array[Symbol]] # # @api public def style_names styles.keys end # Check if provided colors are known colors # # @param [Array[Symbol,String]] # the list of colors to check # # @example # valid?(:red) # => true # # @return [Boolean] # true if all colors are valid, false otherwise # # @api public def valid?(*colors) colors.all? { |color| style_names.include?(color.to_sym) } end # Define a new colors alias # # @param [String] alias_name # the colors alias to define # @param [Array[Symbol,String]] color # the colors the alias will correspond to # # @return [Array[String]] # the standard color values of the alias # # @api public def alias_color(alias_name, *colors) validate(*colors) if !(alias_name.to_s =~ /^[\w]+$/) fail InvalidAliasNameError, "Invalid alias name `#{alias_name}`" elsif ANSI::ATTRIBUTES[alias_name] fail InvalidAliasNameError, "Cannot alias standard color `#{alias_name}`" end ALIASES[alias_name.to_sym] = colors.map(&ANSI::ATTRIBUTES.method(:[])) colors end private # Check if value contains anything to style # # @return [Boolean] # # @api private def blank?(value) value.nil? || !value.respond_to?(:to_str) || value.to_s == '' end # @api private def validate(*colors) return if valid?(*colors) fail InvalidAttributeNameError, 'Bad style or unintialized constant, ' \ " valid styles are: #{style_names.join(', ')}." end end # Color end # TTY pastel-0.7.3/lib/pastel/ansi.rb0000644000175000017500000000257713611565237015730 0ustar boutilboutil# encoding: utf-8 module Pastel # Mixin that provides ANSI codes module ANSI ATTRIBUTES = { clear: 0, reset: 0, bold: 1, dark: 2, dim: 2, italic: 3, underline: 4, underscore: 4, inverse: 7, hidden: 8, strikethrough: 9, black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, on_black: 40, on_red: 41, on_green: 42, on_yellow: 43, on_blue: 44, on_magenta: 45, on_cyan: 46, on_white: 47, bright_black: 90, bright_red: 91, bright_green: 92, bright_yellow: 93, bright_blue: 94, bright_magenta: 95, bright_cyan: 96, bright_white: 97, on_bright_black: 100, on_bright_red: 101, on_bright_green: 102, on_bright_yellow: 103, on_bright_blue: 104, on_bright_magenta: 105, on_bright_cyan: 106, on_bright_white: 107 }.freeze module_function def foreground?(code) [*(30..37), *(90..97)].include?(code.to_i) end def background?(code) [*(40..47), *(100..107)].include?(code.to_i) end def style?(code) (1..9).include?(code.to_i) end end # ANSI end # Pastel pastel-0.7.3/lib/pastel/alias_importer.rb0000644000175000017500000000214413611565237017776 0ustar boutilboutil# encoding: utf-8 module Pastel # A class responsible for importing color aliases class AliasImporter # Create alias importer # # @example # importer = Pastel::AliasImporter.new(Pastel::Color.new, {}) # # @api public def initialize(color, env, output = $stderr) @color = color @env = env @output = output end # Import aliases from the environment # # @example # importer = Pastel::AliasImporter.new(Pastel::Color.new, {}) # importer.import # # @return [nil] # # @api public def import color_aliases = env['PASTEL_COLORS_ALIASES'] return unless color_aliases color_aliases.split(',').each do |color_alias| new_color, old_colors = color_alias.split('=') if !new_color || !old_colors output.puts "Bad color mapping `#{color_alias}`" else color.alias_color(new_color.to_sym, *old_colors.split('.').map(&:to_sym)) end end end protected attr_reader :color, :output, :env end # AliasImporter end # Pastel pastel-0.7.3/lib/pastel.rb0000644000175000017500000000174713611565237014774 0ustar boutilboutil# encoding: utf-8 require 'tty-color' require_relative 'pastel/alias_importer' require_relative 'pastel/color' require_relative 'pastel/color_resolver' require_relative 'pastel/delegator' require_relative 'pastel/decorator_chain' require_relative 'pastel/version' module Pastel # Raised when the style attribute is not supported InvalidAttributeNameError = Class.new(::ArgumentError) # Raised when the color alias is not supported InvalidAliasNameError = Class.new(::ArgumentError) # Create Pastel chainable API # # @example # pastel = Pastel.new enabled: true # # @return [Delegator] # # @api public def new(options = {}) unless options.key?(:enabled) options[:enabled] = (TTY::Color.windows? || TTY::Color.color?) end color = Color.new(options) importer = AliasImporter.new(color, ENV) importer.import resolver = ColorResolver.new(color) Delegator.for(resolver, DecoratorChain.empty) end module_function :new end # Pastel pastel-0.7.3/examples/0000755000175000017500000000000013611565237014216 5ustar boutilboutilpastel-0.7.3/examples/palette.rb0000644000175000017500000000244013611565237016201 0ustar boutilboutilrequire_relative '../lib/pastel' pastel = Pastel.new puts pastel.bold('bold ') + ' ' + pastel.dim('dim ') + ' ' + pastel.italic('italic ') + ' ' + pastel.underline('underline') + ' ' + pastel.inverse('inverse ') + ' ' + pastel.strikethrough('strikethrough') puts pastel.red('red ') + ' ' + pastel.green('green ') + ' ' + pastel.yellow('yellow ') + ' ' + pastel.blue('blue ') + ' ' + pastel.magenta('magenta ') + ' ' + pastel.cyan('cyan ') + ' ' + pastel.white('white') puts pastel.bright_red('red ') + ' ' + pastel.bright_green('green ') + ' ' + pastel.bright_yellow('yellow ') + ' ' + pastel.bright_blue('blue ') + ' ' + pastel.bright_magenta('magenta ') + ' ' + pastel.bright_cyan('cyan ') + ' ' + pastel.bright_white('white') puts pastel.on_red('on_red') + ' ' + pastel.on_green('on_green') + ' ' + pastel.on_yellow('on_yellow') + ' ' + pastel.on_blue('on_blue') + ' ' + pastel.on_magenta('on_magenta') + ' ' + pastel.on_cyan('on_cyan') + ' ' + pastel.on_white('on_white') puts pastel.on_bright_red('on_red') + ' ' + pastel.on_bright_green('on_green') + ' ' + pastel.on_bright_yellow('on_yellow') + ' ' + pastel.on_bright_blue('on_blue') + ' ' + pastel.on_bright_magenta('on_magenta') + ' ' + pastel.on_bright_cyan('on_cyan') + ' ' + pastel.on_bright_white('on_white') pastel-0.7.3/Rakefile0000644000175000017500000000021513611565237014043 0ustar boutilboutil# encoding: utf-8 require "bundler/gem_tasks" FileList['tasks/**/*.rake'].each(&method(:import)) desc 'Run all specs' task ci: %w[ spec ] pastel-0.7.3/README.md0000644000175000017500000002630213611565237013662 0ustar boutilboutil
pastel logo
# Pastel [![Gem Version](https://badge.fury.io/rb/pastel.svg)][gem] [![Build Status](https://secure.travis-ci.org/piotrmurach/pastel.svg?branch=master)][travis] [![Build status](https://ci.appveyor.com/api/projects/status/9blbjfq42o4v1rk4?svg=true)][appveyor] [![Code Climate](https://codeclimate.com/github/piotrmurach/pastel/badges/gpa.svg)][codeclimate] [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/pastel/badge.svg)][coverage] [![Inline docs](http://inch-ci.org/github/piotrmurach/pastel.svg?branch=master)][inchpages] [gem]: http://badge.fury.io/rb/pastel [travis]: http://travis-ci.org/piotrmurach/pastel [appveyor]: https://ci.appveyor.com/project/piotrmurach/pastel [codeclimate]: https://codeclimate.com/github/piotrmurach/pastel [coverage]: https://coveralls.io/github/piotrmurach/pastel [inchpages]: http://inch-ci.org/github/piotrmurach/pastel > Terminal output styling with intuitive and clean API that doesn't monkey patch String class. **Pastel** is minimal and focused to work in all terminal emulators. ![screenshot](https://github.com/piotrmurach/pastel/raw/master/assets/screenshot.png) **Pastel** provides independent coloring component for [TTY](https://github.com/piotrmurach/tty) toolkit. ## Features * Doesn't monkey patch `String` * Intuitive and expressive API * Minimal and focused to work on all terminal emulators * Auto-detection of color support * Allows nested styles * Performant ## Installation Add this line to your application's Gemfile: gem 'pastel' And then execute: $ bundle Or install it yourself as: $ gem install pastel ## Contents * [1. Usage](#1-usage) * [2. Interface](#2-interface) * [2.1 Color](#21-color) * [2.2 Decorate](#22-decorate) * [2.3 Undecorate](#23-undecorate) * [2.4 Detach](#24-detach) * [2.5 Strip](#25-strip) * [2.6 Styles](#26-styles) * [2.7 Lookup](#27-lookup) * [2.8 Valid?](#28-valid) * [2.9 Colored?](#29-colored) * [2.10 Enabled?](#210-enabled) * [2.11 Eachline](#211-eachline) * [2.12 Alias Color](#212-alias-color) * [3. Supported Colors](#3-supported-colors) * [4. Environment](#4-environment) * [5. Command line](#5-command-line) ## 1 Usage **Pastel** provides a simple, minimal and intuitive API for styling your strings: ```ruby pastel = Pastel.new puts pastel.red('Unicorns!') ``` **Pastel** doesn't print the colored string out, just returns it, you'll have to print it yourself. You can compose multiple styles through chainable API: ```ruby pastel.red.on_green.bold('Unicorns!') ``` It allows you to combine styled strings with unstyled ones: ```ruby pastel.red('Unicorns') + ' will rule ' + pastel.green('the World!') ``` It supports variable number of arguments: ```ruby pastel.red('Unicorns', 'are', 'running', 'everywhere!') ``` You can also nest styles as follows: ```ruby pastel.red('Unicorns ', pastel.on_green('everywhere!')) ``` Nesting is smart enough to know where one color ends and another one starts: ```ruby pastel.red('Unicorns ' + pastel.green('everywhere') + pastel.on_yellow('!')) ``` You can also nest styles inside blocks: ```ruby pastel.red.on_green('Unicorns') { green.on_red('will ', 'dominate') { yellow('the world!') } } ``` When dealing with multiline strings you can set `eachline` option(more info see [eachline](#211-eachline)): ``` pastel = Pastel.new(eachline: "\n") ``` You can also predefine needed styles and reuse them: ```ruby error = pastel.red.bold.detach warning = pastel.yellow.detach puts error.('Error!') puts warning.('Warning') ``` If your output is redirected to a file, you probably don't want Pastel to add color to your text. See https://github.com/piotrmurach/pastel#210-enabled for a way to easily accomplish this. **Pastel** has companion library called `pastel-cli` that allows you to style text in terminal via `pastel` executable: ```bash $ pastel green 'Unicorns & rainbows!' ``` ## 2 Interface ### 2.1 Color pastel.`[....](string, [string...])` Color styles are invoked as method calls with a string argument. A given color can take any number of strings as arguments. Then it returns a colored string which isn't printed out to terminal. You need to print it yourself if you need to. This is done so that you can save it as a string, pass to something else, send it to a file handle and so on. ```ruby pastel.red('Unicorns ', pastel.bold.underline('everywhere'), '!') ``` Please refer to [3. Supported Colors](#3-supported-colors) section for full list of supported styles. ### 2.2 Decorate This method is a lower level string styling call that takes as the first argument the string to style followed by any number of color attributes, and returns string wrapped in styles. ```ruby pastel.decorate('Unicorn', :green, :on_blue, :bold) ``` This method will be useful in situations where colors are provided as a list of parameters that have been generated dynamically. ### 2.3 Undecorate It performs the opposite to `decorate` method by turning color escape sequences found in the string into a list of hash objects corresponding with the attribute names set by those sequences. Depending on the parsed string, each hash object may contain `:foreground`, `:background`, `:text` and/or `:style` keys. ```ruby pastel.undecorate("\e[32mfoo\e[0m \e[31mbar\e[0m") # => [{foreground: :green, text: 'foo'}, {text: ' '}, {foreground: :red, text: 'bar'}] ``` To translate the color name into sequence use [lookup](#27-lookup) ### 2.4 Detach The `detach` method allows to keep all the associated colors with the detached instance for later reference. This method is useful when detached colors are being reused frequently and thus shorthand version is preferred. The detached object can be invoked using `call` method or it's shorthand `.()`, as well as array like access `[]`. For example, the following are equivalent examples of detaching colors: ```ruby notice = pastel.blue.bold.detach notice.call('Unicorns running') notice.('Unicorns running') notice['Unicorns running'] ``` ### 2.5 Strip Strip only color sequence characters from the provided strings and preserve any movement codes or other escape sequences. The return value will be either array of modified strings or a single string. The arguments are not modified. ```ruby pastel.strip("\e[1A\e[1m\e[34mbold blue text\e[0m") # => "\e[1Abold blue text" ``` ### 2.6 Styles To get a full list of supported styles with the corresponding color codes do: ```ruby pastel.styles ``` ### 2.7 Lookup To perform translation of color name into ansi escape code use `lookup`: ```ruby pastel.lookup(:red) # => "\e[31m" pastel.lookup(:reset) # => "\e[0m" ``` ### 2.8 Valid? Determine whether a color or a list of colors are valid. `valid?` takes one or more attribute strings or symbols and returns true if all attributes are known and false otherwise. ```ruby pastel.valid?(:red, :blue) # => true pastel.valid?(:unicorn) # => false ``` ### 2.9 Colored? In order to determine if string has color escape codes use `colored?` like so ```ruby pastel.colored?("\e[31mcolorful\e[0m") # => true ``` ### 2.10 Enabled? In order to detect if your terminal supports coloring do: ```ruby pastel.enabled? # => false ``` In cases when the color support is not provided no styling will be applied to the colored string. Moreover, you can force **Pastel** to always print out string with coloring switched on: ```ruby pastel = Pastel.new(enabled: true) pastel.enabled? # => true ``` If you are outputting to stdout or stderr, and want to suppress color if output is redirected to a file, you can set the enabled attribute dynamically, as in: ```ruby stdout_pastel = Pastel.new(enabled: $stdout.tty?) stderr_pastel = Pastel.new(enabled: $stderr.tty?) ``` ### 2.11 Eachline Normally **Pastel** colors string by putting color codes at the beginning and end of the string, but if you provide `eachline` option set to some string, that string will be considered the line delimiter. Consequently, each line will be separately colored with escape sequence and reset code at the end. This option is desirable if the output string contains newlines and you're using background colors. Since color code that spans more than one line is often interpreted by terminal as providing background for all the lines that follow. This in turn may cause programs such as pagers to spill the colors throughout the text. In most cases you will want to set `eachline` to `\n` character like so: ```ruby pastel = Pastel.new(eachline: "\n") pastel.red("foo\nbar") # => "\e[31mfoo\e[0m\n\e[31mbar\e[0m" ``` ### 2.12 Alias Color In order to setup an alias for standard colors do: ```ruby pastel.alias_color(:funky, :red, :bold) ``` From that point forward, `:funky` alias can be passed to `decorate`, `valid?` with the same meaning as standard colors: ```ruby pastel.funky.on_green('unicorn') # => will use :red, :bold color ``` This method allows you to give more meaningful names to existing colors. You can also use the `PASTEL_COLORS_ALIASES` environment variable (see [Environment](#4-environment)) to specify aliases. Note: Aliases are global and affect all callers in the same process. ## 3 Supported Colors **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. The variant with `on_` prefix will style the text background color. The foreground colors: * `black` * `red` * `green` * `yellow` * `blue` * `magenta` * `cyan` * `white` * `bright_black` * `bright_red` * `bright_green` * `bright_yellow` * `bright_blue` * `bright_magenta` * `bright_cyan` * `bright_white` The background colors: * `on_black` * `on_red` * `on_green` * `on_yellow` * `on_blue` * `on_magenta` * `on_cyan` * `on_white` * `on_bright_black` * `on_bright_red` * `on_bright_green` * `on_bright_yellow` * `on_bright_blue` * `on_bright_magenta` * `on_bright_cyan` * `on_bright_white` Generic styles: * `clear` * `bold` * `dim` * `italic` * `underline` * `inverse` * `hidden` * `strikethrough` ## 4 Environment ### 4.1 PASTEL_COLORS_ALIASES This environment variable allows you to specify custom color aliases at runtime that will be understood by **Pastel**. The environment variable is read and used when the instance of **Pastel** is created. You can also use `alias_color` to create aliases. Only alphanumeric and `_` and `.` are allowed in the alias names with the following format: ```ruby PASTEL_COLORS_ALIASES='newcolor_1=red,newcolor_2=on_green,funky=red.bold' ``` ## 5. Command line You can also install [pastel-cli](https://github.com/piotrmurach/pastel-cli) to use `pastel` executable in terminal: ```bash $ pastel green 'Unicorns & rainbows!' ``` ## Contributing 1. Fork it ( https://github.com/piotrmurach/pastel/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request ## Copyright Copyright (c) 2014-2018 Piotr Murach. See LICENSE for further details. pastel-0.7.3/LICENSE.txt0000644000175000017500000000205513611565237014225 0ustar boutilboutilCopyright (c) 2014 Piotr Murach MIT License 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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. pastel-0.7.3/CHANGELOG.md0000644000175000017500000001003613611565237014211 0ustar boutilboutil# Change log ## [v0.7.3] - 2019-06-16 ### Changed * Change gemspec to load required files directly without git * Change to update tty-color & equatable dependency versions ### Fixed * Fix Delegator warning ## [v0.7.2] - 2017-11-09 ### Changed * Change to load relative file paths * Change to allow `#alias_color` to accept multiple colors by Jared Ning (@ordinaryzelig) ## [v0.7.1] - 2017-01-09 ### Changed * Change to load specific files when needed * Change to freeze ANSI attributes * Change to directly assign enabled attribute ## [v0.7.0] - 2016-12-27 ### Changed * Enabled colors on Windows by default * Update tty-color dependency ### Fixed * Fix Color#decorate to prevent redecoration with the same color ## [v0.6.1] - 2016-04-09 ### Fixed * Fix #decorate to apply color to non zero length strings ## [v0.6.0] - 2016-01-15 ### Added * Add helper functions #foreground?, #background?, #style to ANSI module * Add ColorParser for parsing color symbols out of text * Add Pastel#undecorate for parsing color names out of strings ### Changed * Change to use tty-color for color capabilities detection * Change to move enabled option to Pastel#new * Improve performance of Color#lookup * Change Color#decorate performance to be 6x faster! * Change Color DSL styling to be 3x faster! ### Fixed * Fix #strip to only remove color sequences * Fix #decorate to pass through original text when decorating without colors * Fix #decorate to work correctly with nested background colors ## [v0.5.3] - 2015-01-05 ### Fixed * Change gemspec to fix dependencies requirement ## [v0.5.2] - 2015-11-27 (Nov 27, 2015) * Change Color#decorate to accept non-string values and immediately return ## [v0.5.1] - 2015-09-18 ### Added * Add ability to call detached instance with array access ## [v0.5.0] - 2015-09-13 ### Added * Add external dependency to check for color support * Add #colored? to check if string has color escape codes * Add #eachline option to allow coloring of multiline strings ### Changed * Further refine #strip method accuracy ### Fixed * Fix redefining inspect method * Fix string representation for pastel instance ## [v0.4.0] - 2014-11-22 ### Added * Add ability to #detach color combination for later reuse * Add ability to nest styles with blocks ### Fixed * Fix Delegator#respond_to method to correctly report existence of methods ## [v0.3.0] - 2014-11-08 ### Added * Add ability to alias colors through #alias_color method * Add ability to alias colors through the environment variable * Improve performance of Pastel::Color styles and lookup methods ### Fixed * Fix bug concerned with lack of escaping for nested styles ## [v0.2.1] - 2014-10-13 ### Fixed * Fix issue #1 with unitialize dependency ## [v0.2.0] - 2014-10-12 ### Added * Add #supports? to Color to check for terminal color support * Add ability to force color support through :enabled option ### Changed * Change gemspec to include equatable as dependency * Change Delegator to stop creating instances and improve performance [v0.7.3]: https://github.com/peter-murach/pastel/compare/v0.7.2...v0.7.3 [v0.7.2]: https://github.com/peter-murach/pastel/compare/v0.7.1...v0.7.2 [v0.7.1]: https://github.com/peter-murach/pastel/compare/v0.7.0...v0.7.1 [v0.7.0]: https://github.com/peter-murach/pastel/compare/v0.6.1...v0.7.0 [v0.6.1]: https://github.com/peter-murach/pastel/compare/v0.6.0...v0.6.1 [v0.6.0]: https://github.com/peter-murach/pastel/compare/v0.5.3...v0.6.0 [v0.5.3]: https://github.com/peter-murach/pastel/compare/v0.5.2...v0.5.3 [v0.5.2]: https://github.com/peter-murach/pastel/compare/v0.5.1...v0.5.2 [v0.5.1]: https://github.com/peter-murach/pastel/compare/v0.5.0...v0.5.1 [v0.5.0]: https://github.com/peter-murach/pastel/compare/v0.4.0...v0.5.0 [v0.4.0]: https://github.com/peter-murach/pastel/compare/v0.3.0...v0.4.0 [v0.3.0]: https://github.com/peter-murach/pastel/compare/v0.2.1...v0.3.0 [v0.2.1]: https://github.com/peter-murach/pastel/compare/v0.2.0...v0.2.1 [v0.2.0]: https://github.com/peter-murach/pastel/compare/v0.1.0...v0.2.0 [v0.1.0]: https://github.com/peter-murach/pastel/compare/v0.1.0