Colored Diffs #157

Merged
merged 5 commits into from Jul 18, 2012
@@ -36,6 +36,7 @@ def diff_as_string(data_new, data_old)
end
#Handle the last remaining hunk
output << oldhunk.diff(format) << "\n"
+ color_diff output
end
def diff_as_object(actual, expected)
@@ -48,7 +49,7 @@ def diff_as_object(actual, expected)
"between #{actual} and #{expected} is empty. Check the " \
"implementation of #{actual}.==."
else
- diff
+ color_diff diff
end
end
@@ -62,6 +63,32 @@ def context_lines
3
end
+ def color(text, code)
+ "\e[#{code}m#{text}\e[0m"
+ end
+
+ def color_diff(diff)
+ return diff unless RSpec::Matchers.configuration.color?
+
+ red = 31
+ green = 32
+ blue = 34
+
+ lines = diff.lines.map do |line|
+ case line[0].chr
+ when "+"
+ color(line, green)
+ when "-"
+ color(line, red)
+ when "@"
+ line[1].chr == "@" ? color(line, blue) : line
+ else
+ line
+ end
+ end
+ lines.join
+ end
+
def object_to_string(object)
case object
when Hash
@@ -39,6 +39,19 @@ def syntax
syntaxes
end
+ # color config for expectations
+ # fallback if rspec core not available
+ if defined?(RSpec::Core)
+ def color?
+ RSpec.configuration.color
+ end
+ else
+ attr_writer :color
+ def color?
+ @color
+ end
+ end
+
# Adds `should` and `should_not` to the given classes
# or modules. This can be used to ensure `should` works
# properly on things like proxy objects (particular
@@ -4,8 +4,14 @@
module RSpec
module Expectations
describe Differ do
+ context "without --color" do
+
+ before { RSpec::Matchers.configuration.stub(:color? => false) }
+
let(:differ) { RSpec::Expectations::Differ.new }
+ # color disabled context
+
describe '#diff_as_string' do
it "outputs unified diff of two strings" do
expected="foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n"
@@ -149,5 +155,23 @@ def inspect
end
end
end
+
+ context "with --color" do
+ before { RSpec::Matchers.configuration.stub(:color? => true) }
+
+ let(:differ) { RSpec::Expectations::Differ.new }
+
+ it "outputs colored diffs" do
+ expected = "foo bar baz"
+ actual = "foo bang baz"
+ expected_diff = "\n\e[34m@@ -1,2 +1,2 @@\n\e[0m\e[31m-foo bang baz\n\e[0m\e[32m+foo bar baz\n\e[0m"
+
+
+ diff = differ.diff_as_string(expected,actual)
+ diff.should == expected_diff
@alexcoplan
alexcoplan Jul 17, 2012 Contributor

This is the failing test on travis. It fails under 1.8.7, jruby and ree. For some reason, diffs are not even getting touched, even though I have directly stubbed RSpec::Matchers.configuration.color?. This is very odd, as you can see if you look in differ.rb at line 71, diffs are returned only if RSpec::Matchers.configuration.color? returns false.

I'm currently installing 1.8.7 to play around and try and work out why this is breaking.. if anyone has any bright ideas, let me know.

@alexcoplan
alexcoplan Jul 17, 2012 Contributor

OK, have replicated locally with 1.8.7. Currently investigating.

@alexcoplan
alexcoplan Jul 17, 2012 Contributor

Should now be fixed. The problem was that older Ruby implementations don't directly let you access string characters like str[0], you get the character's ascii ordinal instead, so in the switch statement none of my checks for @, + or - were matching. With str[0].chr, this should work across all supported implementations.

+ end
+ end
+
+ end
end
end