170 lines
4.5 KiB
Ruby
170 lines
4.5 KiB
Ruby
#! /usr/env/bin ruby
|
|
#--
|
|
# Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca>
|
|
# adapted from:
|
|
# Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com>
|
|
# Smalltalk by Mario I. Wolczko <mario@wolczko.com>
|
|
# implements McIlroy-Hunt diff algorithm
|
|
#
|
|
# This program is free software. It may be redistributed and/or modified under
|
|
# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
|
|
# Ruby licence.
|
|
#
|
|
# $Id: change.rb,v 1.4 2004/08/08 20:33:09 austin Exp $
|
|
#++
|
|
# Provides Diff::LCS::Change and Diff::LCS::ContextChange.
|
|
|
|
# Centralises the change test code in Diff::LCS::Change and
|
|
# Diff::LCS::ContextChange, since it's the same for both classes.
|
|
module Diff::LCS::ChangeTypeTests
|
|
def deleting?
|
|
@action == '-'
|
|
end
|
|
|
|
def adding?
|
|
@action == '+'
|
|
end
|
|
|
|
def unchanged?
|
|
@action == '='
|
|
end
|
|
|
|
def changed?
|
|
@changed == '!'
|
|
end
|
|
|
|
def finished_a?
|
|
@changed == '>'
|
|
end
|
|
|
|
def finished_b?
|
|
@changed == '<'
|
|
end
|
|
end
|
|
|
|
# Represents a simplistic (non-contextual) change. Represents the removal or
|
|
# addition of an element from either the old or the new sequenced enumerable.
|
|
class Diff::LCS::Change
|
|
# Returns the action this Change represents. Can be '+' (#adding?), '-'
|
|
# (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When created by
|
|
# Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' (#finished_a?) or
|
|
# '<' (#finished_b?).
|
|
attr_reader :action
|
|
attr_reader :position
|
|
attr_reader :element
|
|
|
|
include Comparable
|
|
def ==(other)
|
|
(self.action == other.action) and
|
|
(self.position == other.position) and
|
|
(self.element == other.element)
|
|
end
|
|
|
|
def <=>(other)
|
|
r = self.action <=> other.action
|
|
r = self.position <=> other.position if r.zero?
|
|
r = self.element <=> other.element if r.zero?
|
|
r
|
|
end
|
|
|
|
def initialize(action, position, element)
|
|
@action = action
|
|
@position = position
|
|
@element = element
|
|
end
|
|
|
|
# Creates a Change from an array produced by Change#to_a.
|
|
def to_a
|
|
[@action, @position, @element]
|
|
end
|
|
|
|
def self.from_a(arr)
|
|
Diff::LCS::Change.new(arr[0], arr[1], arr[2])
|
|
end
|
|
|
|
include Diff::LCS::ChangeTypeTests
|
|
end
|
|
|
|
# Represents a contextual change. Contains the position and values of the
|
|
# elements in the old and the new sequenced enumerables as well as the action
|
|
# taken.
|
|
class Diff::LCS::ContextChange
|
|
# Returns the action this Change represents. Can be '+' (#adding?), '-'
|
|
# (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When
|
|
# created by Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>'
|
|
# (#finished_a?) or '<' (#finished_b?).
|
|
attr_reader :action
|
|
attr_reader :old_position
|
|
attr_reader :old_element
|
|
attr_reader :new_position
|
|
attr_reader :new_element
|
|
|
|
include Comparable
|
|
|
|
def ==(other)
|
|
(@action == other.action) and
|
|
(@old_position == other.old_position) and
|
|
(@new_position == other.new_position) and
|
|
(@old_element == other.old_element) and
|
|
(@new_element == other.new_element)
|
|
end
|
|
|
|
def inspect(*args)
|
|
%Q(#<#{self.class.name}:#{__id__} @action=#{action} positions=#{old_position},#{new_position} elements=#{old_element.inspect},#{new_element.inspect}>)
|
|
end
|
|
|
|
def <=>(other)
|
|
r = @action <=> other.action
|
|
r = @old_position <=> other.old_position if r.zero?
|
|
r = @new_position <=> other.new_position if r.zero?
|
|
r = @old_element <=> other.old_element if r.zero?
|
|
r = @new_element <=> other.new_element if r.zero?
|
|
r
|
|
end
|
|
|
|
def initialize(action, old_position, old_element, new_position, new_element)
|
|
@action = action
|
|
@old_position = old_position
|
|
@old_element = old_element
|
|
@new_position = new_position
|
|
@new_element = new_element
|
|
end
|
|
|
|
def to_a
|
|
[@action, [@old_position, @old_element], [@new_position, @new_element]]
|
|
end
|
|
|
|
# Creates a ContextChange from an array produced by ContextChange#to_a.
|
|
def self.from_a(arr)
|
|
if arr.size == 5
|
|
Diff::LCS::ContextChange.new(arr[0], arr[1], arr[2], arr[3], arr[4])
|
|
else
|
|
Diff::LCS::ContextChange.new(arr[0], arr[1][0], arr[1][1], arr[2][0],
|
|
arr[2][1])
|
|
end
|
|
end
|
|
|
|
# Simplifies a context change for use in some diff callbacks. '<' actions
|
|
# are converted to '-' and '>' actions are converted to '+'.
|
|
def self.simplify(event)
|
|
ea = event.to_a
|
|
|
|
case ea[0]
|
|
when '-'
|
|
ea[2][1] = nil
|
|
when '<'
|
|
ea[0] = '-'
|
|
ea[2][1] = nil
|
|
when '+'
|
|
ea[1][1] = nil
|
|
when '>'
|
|
ea[0] = '+'
|
|
ea[1][1] = nil
|
|
end
|
|
|
|
Diff::LCS::ContextChange.from_a(ea)
|
|
end
|
|
|
|
include Diff::LCS::ChangeTypeTests
|
|
end
|