Skip to content

Commit

Permalink
Refactor Colorize
Browse files Browse the repository at this point in the history
  - Add `Colorize::Builder` to build colorized content
  - Work on string interpolation until current, but we can't get TTY detection
  feature in this way.
  • Loading branch information
makenowjust committed Feb 4, 2017
1 parent c7ea511 commit eb9679b
Show file tree
Hide file tree
Showing 31 changed files with 801 additions and 581 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ color ?= auto ## Colorize the output
O := .build
SOURCES := $(shell find src -name '*.cr')
SPEC_SOURCES := $(shell find spec -name '*.cr')
FLAGS := --color=$(color)$(if $(release), --release)$(if $(stats), --stats)$(if $(threads), --threads $(threads))$(if $(debug), -d)
# TODO: Uncomment below after next release.
# FLAGS := --color=$(color)$(if $(release), --release)$(if $(stats), --stats)$(if $(threads), --threads $(threads))$(if $(debug), -d)
FLAGS := $(if $(release),--release )$(if $(stats),--stats )$(if $(threads),--threads $(threads) )$(if $(debug),-d )
VERBOSE := $(if $(verbose),-v )
COLOR := --color=$(color)
EXPORTS := $(if $(release),,CRYSTAL_CONFIG_PATH=`pwd`/src)
Expand Down
4 changes: 1 addition & 3 deletions spec/compiler/semantic/did_you_mean_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,6 @@ describe "Semantic: did you mean" do
end

it "suggests a better alternative to logical operators (#2715)" do
message = "undefined method 'and'"
message = " (did you mean '&&'?)".colorize.yellow.bold.to_s
assert_error %(
def rand(x : Int32)
end
Expand All @@ -252,7 +250,7 @@ describe "Semantic: did you mean" do
if "a".bytes and 1
1
end
), message
), "did you mean '&&'?"
end

it "says did you mean in instance var declaration" do
Expand Down
2 changes: 1 addition & 1 deletion spec/compiler/semantic/generic_class_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ describe "Semantic: generic class" do
semantic(nodes)
rescue ex : TypeException
msg = ex.to_s.lines.map(&.strip)
msg.count("- Foo(T).foo(x : Int32)").should eq(1)
msg.count(&.includes? "- Foo(T).foo(x : Int32)").should eq(1)
end
end

Expand Down
255 changes: 168 additions & 87 deletions spec/std/colorize_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@ require "spec"
require "colorize"

private class FakeTTY < IO::Memory
def tty?
true
end
include Colorize::ColorizableIO

@colorize_when = Colorize::When::Always

property? tty = false

INSTANCE = new
end

private def colorize(obj, io = IO::Memory.new, **args)
if obj
yield(obj.colorize(**args).when(:always).when(args[:when]?)).to_s io
else
yield(with_color(**args).when(:always).when(args[:when]?)).as(Colorize::Style).surround(io) { }
private def colorize(obj, tty = true, colorize_when = Colorize::When::Always, **args)
io = FakeTTY::INSTANCE

begin
io.colorize_when = colorize_when
io.tty = tty
if obj
io << yield obj.colorize **args
else
io.surround(yield with_color **args) { }
end
ensure
io.colorize_when = Colorize::When::Always
io.tty = false
end
io.to_s

io.to_s.tap { io.clear }
end

private def colorize(obj, **args)
Expand Down Expand Up @@ -152,79 +166,44 @@ describe Colorize do
end

it "colorizes when given io is TTY on 'auto' policy" do
colorize(obj, when: :auto, &.black).should eq("")
colorize(obj, when: "auto", &.black).should eq("")
colorize(obj, when: Colorize::When::Auto, &.black).should eq("")
colorize(obj, &.black.auto).should eq("")
colorize(obj, &.black.when(:auto)).should eq("")
colorize(obj, &.black.when("auto")).should eq("")
colorize(obj, &.black.when(Colorize::When::Auto)).should eq("")

colorize(obj, io: FakeTTY.new, when: :auto, &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, when: "auto", &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, when: Colorize::When::Auto, &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.auto).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when(:auto)).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when("auto")).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when(Colorize::When::Auto)).should eq("\e[30m\e[0m")
colorize(obj, tty: false, colorize_when: :auto, &.black).should eq("")
colorize(obj, tty: false, colorize_when: "auto", &.black).should eq("")
colorize(obj, tty: false, colorize_when: Colorize::When::Auto, &.black).should eq("")

colorize(obj, tty: true, colorize_when: :auto, &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: true, colorize_when: "auto", &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: true, colorize_when: Colorize::When::Auto, &.black).should eq("\e[30m\e[0m")
end

it "colorizes always" do
colorize(obj, when: :always, &.black).should eq("\e[30m\e[0m")
colorize(obj, when: "always", &.black).should eq("\e[30m\e[0m")
colorize(obj, when: Colorize::When::Always, &.black).should eq("\e[30m\e[0m")
colorize(obj, &.black.always).should eq("\e[30m\e[0m")
colorize(obj, &.black.when(:always)).should eq("\e[30m\e[0m")
colorize(obj, &.black.when("always")).should eq("\e[30m\e[0m")
colorize(obj, &.black.when(Colorize::When::Always)).should eq("\e[30m\e[0m")

colorize(obj, io: FakeTTY.new, when: :always, &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, when: "always", &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, when: Colorize::When::Always, &.black).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.always).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when(:always)).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when("always")).should eq("\e[30m\e[0m")
colorize(obj, io: FakeTTY.new, &.black.when(Colorize::When::Always)).should eq("\e[30m\e[0m")
colorize(obj, tty: false, colorize_when: :always, &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: false, colorize_when: "always", &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: false, colorize_when: Colorize::When::Always, &.black).should eq("\e[30m\e[0m")

colorize(obj, tty: true, colorize_when: :always, &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: true, colorize_when: "always", &.black).should eq("\e[30m\e[0m")
colorize(obj, tty: true, colorize_when: Colorize::When::Always, &.black).should eq("\e[30m\e[0m")
end

it "colorizes never" do
colorize(obj, when: :never, &.black).should eq("")
colorize(obj, when: "never", &.black).should eq("")
colorize(obj, when: Colorize::When::Never, &.black).should eq("")
colorize(obj, &.black.never).should eq("")
colorize(obj, &.black.when(:never)).should eq("")
colorize(obj, &.black.when("never")).should eq("")
colorize(obj, &.black.when(Colorize::When::Never)).should eq("")

colorize(obj, io: FakeTTY.new, when: :never, &.black).should eq("")
colorize(obj, io: FakeTTY.new, when: "never", &.black).should eq("")
colorize(obj, io: FakeTTY.new, when: Colorize::When::Never, &.black).should eq("")
colorize(obj, io: FakeTTY.new, &.black.never).should eq("")
colorize(obj, io: FakeTTY.new, &.black.when(:never)).should eq("")
colorize(obj, io: FakeTTY.new, &.black.when("never")).should eq("")
colorize(obj, io: FakeTTY.new, &.black.when(Colorize::When::Never)).should eq("")
colorize(obj, tty: false, colorize_when: :never, &.black).should eq("")
colorize(obj, tty: false, colorize_when: "never", &.black).should eq("")
colorize(obj, tty: false, colorize_when: Colorize::When::Never, &.black).should eq("")

colorize(obj, tty: true, colorize_when: :never, &.black).should eq("")
colorize(obj, tty: true, colorize_when: "never", &.black).should eq("")
colorize(obj, tty: true, colorize_when: Colorize::When::Never, &.black).should eq("")
end

it "is chainable but apply only last" do
colorize(obj, &.blue.red).should eq("\e[31m\e[0m")
colorize(obj, &.on_blue.on_red).should eq("\e[41m\e[0m")
colorize(obj, &.always.never).should eq("")
end

it "toggles off" do
colorize(obj, &.black.toggle(false)).should eq("")
colorize(obj, &.toggle(false).black).should eq("")
end

it "toggles off and on" do
colorize(obj, io: FakeTTY.new, &.toggle(false).black.toggle(true)).should eq("\e[30m\e[0m")
end

it "is chainable, `nil` has no effect" do
it "is chainable, nil has no effect" do
colorize(obj, &.blue.fore(nil)).should eq("\e[34m\e[0m")
colorize(obj, &.on_blue.back(nil)).should eq("\e[44m\e[0m")
colorize(obj, &.bold.mode(nil)).should eq("\e[1m\e[0m")
colorize(obj, io: FakeTTY.new, &.when(:never).when(nil)).should eq("")
end

it "raises on unknown foreground color" do
Expand All @@ -247,13 +226,59 @@ describe Colorize do
end
end

describe Colorize::Style do
describe Colorize::IOExtension do
describe "colorizable" do
it "creates a new Colorize::ColorizableIO instance" do
original = IO::Memory.new
colorizable = original.to_colorizable
colorizable.should be_a(Colorize::ColorizableIO)
colorizable.should_not be(original)
end

it "returns itself if it is a Colorize::ColorizableIO" do
original = FakeTTY.new
colorizable = original.to_colorizable
colorizable.should be_a(Colorize::ColorizableIO)
colorizable.should be(original)
end
end
end

describe Colorize::ColorizableIO do
it "IO::FileDescriptor is a Colorize::ColorizableIO" do
File.open(__FILE__) do |f|
f.should be_a(Colorize::ColorizableIO)
end
end

describe "#colorize_when" do
it "default value on IO::FileDescriptor is Colorize::When::Auto" do
File.open(__FILE__) do |f|
f.colorize_when.should eq(Colorize::When::Auto)
end
end
end

describe "#colorize_when=" do
it "raises on unknown policy symbol" do
expect_raises ArgumentError, "unknown policy: bad" do
FakeTTY.new.colorize_when = :bad
end
end

it "raises on unknown policy string" do
expect_raises ArgumentError, "unknown policy: bad" do
FakeTTY.new.colorize_when = "bad"
end
end
end

describe "#surround" do
it "colorizes with surround stack" do
FakeTTY.new.tap do |io|
with_color.red.surround(io) do |io|
io.surround(with_color.red) do |io|
io << "hello"
with_color.green.bold.surround(io) do |io|
io.surround(with_color.green.bold) do |io|
io << "world"
end
io << "bye"
Expand All @@ -263,19 +288,19 @@ describe Colorize do

it "colorizes with surround stack having Object" do
FakeTTY.new.tap do |io|
with_color.red.surround(io) do |io|
io.surround(with_color.red) do |io|
io << "hello"
"world".colorize.green.bold.to_s io
io << "world".colorize.green.bold
io << "bye"
end
end.to_s.should eq("\e[31mhello\e[0;32;1mworld\e[0;31mbye\e[0m")
end

it "colorizes with surround stack having same styles" do
FakeTTY.new.tap do |io|
with_color.red.surround(io) do |io|
io.surround(with_color.red) do |io|
io << "hello"
with_color.red.surround(io) do |io|
io.surround(with_color.red) do |io|
io << "world"
end
io << "bye"
Expand All @@ -284,25 +309,81 @@ describe Colorize do
end

it "colorizes with surround stack having default styles" do
io = FakeTTY.new
with_color.surround(io) do |io|
io << "hello"
with_color.surround(io) do |io|
io << "foo"
with_color.green.surround(io) do |io|
io << "fizz"
with_color.surround(io) do |io|
io << "world"
FakeTTY.new.tap do |io|
io.surround(with_color) do |io|
io << "hello"
io.surround(with_color) do |io|
io << "foo"
io.surround(with_color.green) do |io|
io << "fizz"
io.surround(with_color) do |io|
io << "world"
end
io << "buzz"
end
io << "buzz"
io << "bar"
end
io << "bar"
io << "bye"
end
io << "bye"
end.to_s.should eq("hellofoo\e[32mfizz\e[0mworld\e[32mbuzz\e[0mbarbye")
end
end
end

describe Colorize::Builder do
describe "#<<" do
it "accepts some objects" do
io = Colorize::Builder.new
(io << "foo" << :foo << 1).should be(io)
end

it "accepts Colorize::Object" do
io = Colorize::Builder.new
(io << "foo".colorize.red << "bar".colorize.blue).should be(io)
end

it "accepts mixed objects" do
io = Colorize::Builder.new
(io << "foo".colorize.red << :bar << 42).should be(io)
end
end

describe "#surround" do
it "creates a new builder" do
io = Colorize::Builder.new
io.surround(with_color.red) do |io2|
io2.puts "foo".colorize.bold
io.should_not be(io2)
end
end

it "yields the block with a new builder" do
io = Colorize::Builder.new
io.surround(with_color.red) do |io|
puts "foo".colorize.bold
itself.should be(io)
end
io.to_s.should eq("hellofoo\e[32mfizz\e[0mworld\e[32mbuzz\e[0mbarbye")
end
end

describe "#to_s" do
it "outputs objects" do
io = Colorize::Builder.new
io << "foo" << :foo << 1
io.to_s.should eq("foofoo1")
end

it "outputs Colorize::Object" do
io = Colorize::Builder.new
io << "foo".colorize.red << "bar".colorize.blue
io.to_s.should eq("\e[31mfoo\e[0m\e[34mbar\e[0m")
end

it "outputs mixed objects" do
io = Colorize::Builder.new
io << "foo".colorize.red << :bar << 42
io.to_s.should eq("\e[31mfoo\e[0mbar42")
end
end
end
end

16 changes: 0 additions & 16 deletions spec/std/spec_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,3 @@ describe "Spec matchers" do
end
end
end

describe "Spec" do
describe "use_colors" do
it "returns if output is colored or not" do
saved = Spec.use_colors
begin
Spec.use_colors = Colorize::When::Never
Spec.use_colors.should eq(Colorize::When::Never)
Spec.use_colors = Colorize::When::Auto
Spec.use_colors.should eq(Colorize::When::Auto)
ensure
Spec.use_colors = saved
end
end
end
end
Loading

0 comments on commit eb9679b

Please sign in to comment.