Skip to content

Instantly share code, notes, and snippets.

@Antti
Created December 9, 2013 10:07
Show Gist options
  • Select an option

  • Save Antti/7869995 to your computer and use it in GitHub Desktop.

Select an option

Save Antti/7869995 to your computer and use it in GitHub Desktop.
require "diff/lcs"
require "diff/lcs/hunk"
require 'pp'
class Differ
def initialize(actual, expected)
@actual = actual
@expected = expected
end
def hunks
@file_length_difference = 0
@hunks ||= diffs.map do |piece|
build_hunk(piece)
end
end
private
def diffs
Diff::LCS.diff(expected_lines, actual_lines)
end
def expected_lines
@expected.split("\n").map! { |e| e.chomp }
end
def actual_lines
@actual.split("\n").map! { |e| e.chomp }
end
def build_hunk(piece)
Diff::LCS::Hunk.new(
expected_lines, actual_lines, piece, context_lines, @file_length_difference
).tap do |h|
@file_length_difference = h.file_length_difference
end
end
def context_lines
3
end
end
class DiffPresenter
def diff_as_string(actual, expected)
@actual = actual
@expected = expected
output = "\n"
hunks.each_cons(2) do |prev_hunk, current_hunk|
begin
if current_hunk.overlaps?(prev_hunk)
add_old_hunk_to_hunk(current_hunk, prev_hunk)
else
add_to_output(output, prev_hunk.diff(format).to_s)
end
ensure
add_to_output(output, "\n")
end
end
if hunks.last
finalize_output(output, hunks.last.diff(format).to_s)
end
color_diff output
end
def diff_as_object(actual, expected)
actual_as_string = object_to_string(actual)
expected_as_string = object_to_string(expected)
if (diff = diff_as_string(actual_as_string, expected_as_string))
color_diff diff
end
end
private
def hunks
@hunks ||= Differ.new(@actual, @expected).hunks
end
def finalize_output(output, final_line)
add_to_output(output, final_line)
add_to_output(output, "\n")
end
def add_to_output(output, string)
output << string
end
def add_old_hunk_to_hunk(hunk, oldhunk)
hunk.merge(oldhunk)
end
def format
:unified
end
def color(text, color_code)
"\e[#{color_code}m#{text}\e[0m"
end
def red(text)
color(text, 31)
end
def green(text)
color(text, 32)
end
def blue(text)
color(text, 34)
end
def color_diff(diff)
diff.lines.map { |line|
case line[0].chr
when "+"
green line
when "-"
red line
when "@"
line[1].chr == "@" ? blue(line) : line
else
line
end
}.join
end
def object_to_string(object)
case object
when Hash
object.keys.sort_by { |k| k.to_s }.map do |key|
pp_key = PP.singleline_pp(key, "")
pp_value = PP.singleline_pp(object[key], "")
"#{pp_key} => #{pp_value}"
end.join(",\n")
when String
object =~ /\n/ ? object : object.inspect
else
PP.pp(object, "")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment