class RSpec::Support::Differ

Attributes

color[R]
color?[R]

Public Class Methods

new(opts={}) click to toggle source
# File lib/rspec/support/differ.rb, line 63
def initialize(opts={})
  @color = opts.fetch(:color, false)
  @object_preparer = opts.fetch(:object_preparer, lambda { |string| string })
end

Public Instance Methods

diff(actual, expected) click to toggle source
# File lib/rspec/support/differ.rb, line 9
def diff(actual, expected)
  diff = ""

  if actual && expected
    if all_strings?(actual, expected)
      if any_multiline_strings?(actual, expected)
        diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected))
      end
    elsif no_procs?(actual, expected) && no_numbers?(actual, expected)
      diff = diff_as_object(actual, expected)
    end
  end

  diff.to_s
end
diff_as_object(actual, expected) click to toggle source
# File lib/rspec/support/differ.rb, line 54
def diff_as_object(actual, expected)
  actual_as_string = object_to_string(actual)
  expected_as_string = object_to_string(expected)
  diff_as_string(actual_as_string, expected_as_string)
end
diff_as_string(actual, expected) click to toggle source
# File lib/rspec/support/differ.rb, line 25
def diff_as_string(actual, expected)
  @encoding = pick_encoding actual, expected

  @actual   = EncodedString.new(actual, @encoding)
  @expected = EncodedString.new(expected, @encoding)

  output = EncodedString.new("\n", @encoding)

  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
rescue Encoding::CompatibilityError
  handle_encoding_errors
end

Private Instance Methods

add_old_hunk_to_hunk(hunk, oldhunk) click to toggle source
# File lib/rspec/support/differ.rb, line 124
def add_old_hunk_to_hunk(hunk, oldhunk)
  hunk.merge(oldhunk)
end
add_to_output(output, string) click to toggle source
# File lib/rspec/support/differ.rb, line 120
def add_to_output(output, string)
  output << string
end
all_strings?(*args) click to toggle source
# File lib/rspec/support/differ.rb, line 74
def all_strings?(*args)
  args.flatten.all? { |a| String === a}
end
any_multiline_strings?(*args) click to toggle source
# File lib/rspec/support/differ.rb, line 78
def any_multiline_strings?(*args)
  all_strings?(*args) && args.flatten.any? { |a| multiline?(a) }
end
blue(text) click to toggle source
# File lib/rspec/support/differ.rb, line 144
def blue(text)
  color(text, 34)
end
coerce_to_string(string_or_array) click to toggle source
# File lib/rspec/support/differ.rb, line 86
def coerce_to_string(string_or_array)
  return string_or_array unless Array === string_or_array
  diffably_stringify(string_or_array).join("\n")
end
color_diff(diff) click to toggle source
# File lib/rspec/support/differ.rb, line 152
def color_diff(diff)
  return diff unless color?

  diff.lines.map { |line|
    case line[0].chr
    when "+"
      green line
    when "-"
      red line
    when "@"
      line[1].chr == "@" ? blue(line) : normal(line)
    else
      normal(line)
    end
  }.join
end
diffably_stringify(array) click to toggle source
# File lib/rspec/support/differ.rb, line 91
def diffably_stringify(array)
  array.map do |entry|
    if Array === entry
      entry.inspect
    else
      entry.to_s.gsub("\n", "\\n")
    end
  end
end
finalize_output(output, final_line) click to toggle source
# File lib/rspec/support/differ.rb, line 115
def finalize_output(output, final_line)
  add_to_output(output, final_line)
  add_to_output(output, "\n")
end
format() click to toggle source
# File lib/rspec/support/differ.rb, line 128
def format
  :unified
end
green(text) click to toggle source
# File lib/rspec/support/differ.rb, line 140
def green(text)
  color(text, 32)
end
handle_encoding_errors() click to toggle source
# File lib/rspec/support/differ.rb, line 195
def handle_encoding_errors
  if @actual.source_encoding != @expected.source_encoding
    "Could not produce a diff because the encoding of the actual string (#{@actual.source_encoding}) "+
      "differs from the encoding of the expected string (#{@expected.source_encoding})"
  else
    "Could not produce a diff because of the encoding of the string (#{@expected.source_encoding})"
  end
end
hunks() click to toggle source
# File lib/rspec/support/differ.rb, line 111
def hunks
  @hunks ||= HunkGenerator.new(@actual, @expected).hunks
end
multiline?(string) click to toggle source
# File lib/rspec/support/differ.rb, line 102
def multiline?(string)
  string.include?("\n".encode(string.encoding))
end
no_numbers?(*args) click to toggle source
# File lib/rspec/support/differ.rb, line 82
def no_numbers?(*args)
  args.flatten.none? { |a| Numeric === a}
end
no_procs?(*args) click to toggle source
# File lib/rspec/support/differ.rb, line 70
def no_procs?(*args)
  args.flatten.none? { |a| Proc === a}
end
normal(text) click to toggle source
# File lib/rspec/support/differ.rb, line 148
def normal(text)
  color(text, 0)
end
object_to_string(object) click to toggle source
# File lib/rspec/support/differ.rb, line 169
def object_to_string(object)
  object = @object_preparer.call(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
pick_encoding(source_a, source_b) click to toggle source
# File lib/rspec/support/differ.rb, line 187
def pick_encoding(source_a, source_b)
  Encoding.compatible?(source_a, source_b) || Encoding.default_external
end
red(text) click to toggle source
# File lib/rspec/support/differ.rb, line 136
def red(text)
  color(text, 31)
end