Created
December 9, 2013 10:07
-
-
Save Antti/7869995 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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