123456789_123456789_123456789_123456789_123456789_

Class: Test::Unit::Diff::ReadableDiffer

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Differ
Instance Chain:
self, Differ
Inherits: Test::Unit::Diff::Differ
Defined in: lib/test/unit/diff.rb

Class Method Summary

Differ - Inherited

Instance Method Summary

Constructor Details

This class inherits a constructor from Test::Unit::Diff::Differ

Instance Method Details

#_diff_lines(from_start, from_end, to_start, to_end) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 528

def _diff_lines(from_start, from_end, to_start, to_end)
  if from_start < from_end
    if to_start < to_end
      diff_lines(from_start, from_end, to_start, to_end)
    else
      tag_deleted(@from[from_start...from_end])
    end
  else
    tag_inserted(@to[to_start...to_end])
  end
end

#compute_width(line, start, _end) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 550

def compute_width(line, start, _end)
  if line.respond_to?(:encoding) and
      Encoding.compatible?(Encoding::UTF_8, line.encoding)
    utf8_line = line[start..._end].encode(Encoding::UTF_8)
    width = 0
    utf8_line.each_codepoint do |unicode_codepoint|
      if UTF8Line.wide_character?(unicode_codepoint)
        width += 2
      else
        width += 1
      end
    end
    width
  elsif line.is_a?(UTF8Line)
    line.compute_width(start, _end)
  else
    _end - start
  end
end

#cut_off_ratio (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 446

def cut_off_ratio
  0.75
end

#default_ratio (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 442

def default_ratio
  0.74
end

#diff(options = {})

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 413

def diff(options={})
  @result = []
  operations.each do |tag, from_start, from_end, to_start, to_end|
    case tag
    when :replace
      diff_lines(from_start, from_end, to_start, to_end)
    when :delete
      tag_deleted(@from[from_start...from_end])
    when :insert
      tag_inserted(@to[to_start...to_end])
    when :equal
      tag_equal(@from[from_start...from_end])
    else
      raise "unknown tag: #{tag}"
    end
  end
  @result
end

#diff_line(from_line, to_line) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 570

def diff_line(from_line, to_line)
  from_tags = ""
  to_tags = ""
  from_line, to_line, _operations = line_operations(from_line, to_line)
  _operations.each do |tag, from_start, from_end, to_start, to_end|
    from_width = compute_width(from_line, from_start, from_end)
    to_width = compute_width(to_line, to_start, to_end)
    case tag
    when :replace
      from_tags += "^" * from_width
      to_tags += "^" * to_width
    when :delete
      from_tags += "-" * from_width
    when :insert
      to_tags += "+" * to_width
    when :equal
      from_tags += " " * from_width
      to_tags += " " * to_width
    else
      raise "unknown tag: #{tag}"
    end
  end
  format_diff_point(from_line, to_line, from_tags, to_tags)
end

#diff_lines(from_start, from_end, to_start, to_end) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 500

def diff_lines(from_start, from_end, to_start, to_end)
  info = find_diff_line_info(from_start, from_end, to_start, to_end)
  best_ratio, from_equal_index, to_equal_index, *info = info
  from_best_index, to_best_index = info
  from_best_index ||= from_start
  to_best_index ||= to_start

  if best_ratio < cut_off_ratio
    if from_equal_index.nil?
      if to_end - to_start < from_end - from_start
        tag_inserted(@to[to_start...to_end])
        tag_deleted(@from[from_start...from_end])
      else
        tag_deleted(@from[from_start...from_end])
        tag_inserted(@to[to_start...to_end])
      end
      return
    end
    from_best_index = from_equal_index
    to_best_index = to_equal_index
    best_ratio = 1.0
  end

  _diff_lines(from_start, from_best_index, to_start, to_best_index)
  diff_line(@from[from_best_index], @to[to_best_index])
  _diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end)
end

#find_diff_line_info(from_start, from_end, to_start, to_end) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 472

def find_diff_line_info(from_start, from_end, to_start, to_end)
  best_ratio = default_ratio
  from_equal_index = to_equal_index = nil
  from_best_index = to_best_index = nil

  to_start.upto(to_end - 1) do |to_index|
    from_start.upto(from_end - 1) do |from_index|
      if @from[from_index] == @to[to_index]
        from_equal_index ||= from_index
        to_equal_index ||= to_index
        next
      end

      matcher = SequenceMatcher.new(@from[from_index], @to[to_index],
                                    &method(:space_character?))
      if matcher.ratio > best_ratio
        best_ratio = matcher.ratio
        from_best_index = from_index
        to_best_index = to_index
      end
    end
  end

  [best_ratio,
   from_equal_index, to_equal_index,
   from_best_index,  to_best_index]
end

#format_diff_point(from_line, to_line, from_tags, to_tags) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 595

def format_diff_point(from_line, to_line, from_tags, to_tags)
  common = [n_leading_characters(from_line, ?\t),
            n_leading_characters(to_line, ?\t)].min
  common = [common,
            n_leading_characters(from_tags[0, common], " "[0])].min
  from_tags = from_tags[common..-1].rstrip
  to_tags = to_tags[common..-1].rstrip

  tag_deleted([from_line])
  unless from_tags.empty?
    tag_difference(["#{"\t" * common}#{from_tags}"])
  end
  tag_inserted([to_line])
  unless to_tags.empty?
    tag_difference(["#{"\t" * common}#{to_tags}"])
  end
end

#line_operations(from_line, to_line) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 540

def line_operations(from_line, to_line)
  if !from_line.respond_to?(:force_encoding) and $KCODE == "UTF8"
    from_line = UTF8Line.new(from_line)
    to_line = UTF8Line.new(to_line)
  end
  matcher = SequenceMatcher.new(from_line, to_line,
                                &method(:space_character?))
  [from_line, to_line, matcher.operations]
end

#n_leading_characters(string, character) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 613

def n_leading_characters(string, character)
  n = 0
  while string[n] == character
    n += 1
  end
  n
end

#operations (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 433

def operations
  @operations ||= nil
  if @operations.nil?
    matcher = SequenceMatcher.new(@from, @to)
    @operations = matcher.operations
  end
  @operations
end

#space_character?(character) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 621

def space_character?(character)
  [" "[0], "\t"[0]].include?(character)
end

#tag(mark, contents) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 450

def tag(mark, contents)
  contents.each do |content|
    @result << (mark + content)
  end
end

#tag_deleted(contents) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 456

def tag_deleted(contents)
  tag("- ", contents)
end

#tag_difference(contents) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 468

def tag_difference(contents)
  tag("? ", contents)
end

#tag_equal(contents) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 464

def tag_equal(contents)
  tag("  ", contents)
end

#tag_inserted(contents) (private)

[ GitHub ]

  
# File 'lib/test/unit/diff.rb', line 460

def tag_inserted(contents)
  tag("+ ", contents)
end