123456789_123456789_123456789_123456789_123456789_

Class: RSpec::Support::Differ

Relationships & Source Files
Inherits: Object
Defined in: rspec-support/lib/rspec/support/differ.rb

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(opts = {}) ⇒ Differ

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 90

def initialize(opts={})
  @color = opts.fetch(:color, false)
  @object_preparer = opts.fetch(:object_preparer, lambda { |string| string })
end

Instance Attribute Details

#color?Boolean (readonly)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 86

def color?
  @color
end

Instance Method Details

#add_old_hunk_to_hunk(hunk, oldhunk) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 155

def add_old_hunk_to_hunk(hunk, oldhunk)
  hunk.merge(oldhunk)
end

#add_to_output(output, string) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 151

def add_to_output(output, string)
  output << string
end

#all_hashes?(actual, expected) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 101

def all_hashes?(actual, expected)
  (Hash === actual) && (Hash === expected)
end

#all_strings?(*args) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 105

def all_strings?(*args)
  safely_flatten(args).all? { |a| String === a }
end

#any_multiline_strings?(*args) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 109

def any_multiline_strings?(*args)
  all_strings?(*args) && safely_flatten(args).any? { |a| multiline?(a) }
end

#blue(text) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 180

def blue(text)
  color(text, 34)
end

#build_hunks(actual, expected) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 142

def build_hunks(actual, expected)
  HunkGenerator.new(actual, expected).hunks
end

#coerce_to_string(string_or_array) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 117

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(text, color_code) (readonly, private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 168

def color(text, color_code)
  "\e[#{color_code}m#{text}\e[0m"
end

#color_diff(diff) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 188

def color_diff(diff)
  return diff unless color?

  diff.lines.map do |line|
    case line[0].chr
    when "+"
      green line
    when "-"
      red line
    when "@"
      line[1].chr == "@" ? blue(line) : normal(line)
    else
      normal(line)
    end
  end.join
end

#diff(actual, expected)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 13

def diff(actual, expected)
  diff = ""

  unless actual.nil? || expected.nil?
    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 all_hashes?(actual, expected)
      diff = diff_hashes_as_object(actual, expected)
    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)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 80

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)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 32

def diff_as_string(actual, expected)
  encoding = EncodedString.pick_encoding(actual, expected)

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

  output = EncodedString.new("\n", encoding)
  hunks = build_hunks(actual, expected)

  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_type).to_s)
      end
    ensure
      add_to_output(output, "\n")
    end
  end

  finalize_output(output, hunks.last.diff(format_type).to_s) if hunks.last

  color_diff output
rescue Encoding::CompatibilityError
  handle_encoding_errors(actual, expected)
end

#diff_hashes_as_object(actual, expected)

See additional method definition at line 62.

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 75

def diff_hashes_as_object(actual, expected)
  actual_to_diff =
    actual.keys.reduce({}) do |hash, key|
      if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === expected[key]
        hash[key] = expected[key]
      else
        hash[key] = actual[key]
      end
      hash
    end
  diff_as_object(actual_to_diff, expected)
end

#diffably_stringify(array) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 122

def diffably_stringify(array)
  array.map do |entry|
    if Array === entry
      entry.inspect
    else
      entry.to_s.gsub("\n", "\\n").gsub("\r", "\\r")
    end
  end
end

#finalize_output(output, final_line) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 146

def finalize_output(output, final_line)
  add_to_output(output, final_line)
  add_to_output(output, "\n")
end

#format_type (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 164

def format_type
  :unified
end

#green(text) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 176

def green(text)
  color(text, 32)
end

#handle_encoding_errors(actual, expected) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 229

def handle_encoding_errors(actual, expected)
  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

#hash_to_string(hash) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 219

def hash_to_string(hash)
  formatted_hash = ObjectFormatter.prepare_for_inspection(hash)
  formatted_hash.keys.sort_by { |k| k.to_s }.map do |key|
    pp_key   = PP.singleline_pp(key, "".dup)
    pp_value = PP.singleline_pp(formatted_hash[key], "".dup)

    "#{pp_key} => #{pp_value},"
  end.join("\n")
end

#multiline?(string) (private)

See additional method definition at line 133.

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 137

def multiline?(string)
  string.include?("\n".encode(string.encoding))
end

#no_numbers?(*args) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 113

def no_numbers?(*args)
  safely_flatten(args).none? { |a| Numeric === a }
end

#no_procs?(*args) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 97

def no_procs?(*args)
  safely_flatten(args).none? { |a| Proc === a }
end

#normal(text) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 184

def normal(text)
  color(text, 0)
end

#object_to_string(object) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 205

def object_to_string(object)
  object = @object_preparer.call(object)
  case object
  when Hash
    hash_to_string(object)
  when Array
    PP.pp(ObjectFormatter.prepare_for_inspection(object), "".dup)
  when String
    object =~ /\n/ ? object : object.inspect
  else
    PP.pp(object, "".dup)
  end
end

#red(text) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 172

def red(text)
  color(text, 31)
end

#safely_flatten(array) (private)

[ GitHub ]

  
# File 'rspec-support/lib/rspec/support/differ.rb', line 159

def safely_flatten(array)
  array = array.flatten(1) until (array == array.flatten(1))
  array
end