#! /usr/env/bin ruby #-- # Copyright 2004 Austin Ziegler # adapted from: # Algorithm::Diff (Perl) by Ned Konz # Smalltalk by Mario I. Wolczko # 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