diff options
Diffstat (limited to 'lib/diff/lcs/change.rb')
-rw-r--r-- | lib/diff/lcs/change.rb | 209 |
1 files changed, 109 insertions, 100 deletions
diff --git a/lib/diff/lcs/change.rb b/lib/diff/lcs/change.rb index 5139821..50c1de9 100644 --- a/lib/diff/lcs/change.rb +++ b/lib/diff/lcs/change.rb @@ -1,59 +1,59 @@ -#! /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$ -#++ +# -*- ruby encoding: utf-8 -*- # 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 +# 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 + # The only actions valid for changes are '+' (add), '-' (delete), '=' + # (no change), '!' (changed), '<' (tail changes from first sequence), or + # '>' (tail changes from second sequence). The last two ('<>') are only + # found with Diff::LCS::diff and Diff::LCS::sdiff. + VALID_ACTIONS = %W(+ - = ! > <) - def adding? - @action == '+' + def self.valid_action?(action) + VALID_ACTIONS.include? action end - def unchanged? - @action == '=' - end + # Returns the action this Change represents. + attr_reader :action - def changed? - @action == '!' + # Returns the position of the Change. + attr_reader :position + # Returns the sequence element of the Change. + attr_reader :element + + def initialize(*args) + @action, @position, @element = *args + + unless Diff::LCS::Change.valid_action?(@action) + raise "Invalid Change Action '#{@action}'" + end + raise "Invalid Position Type" unless @position.kind_of? Fixnum end - def finished_a? - @action == '>' + def inspect + %Q(#<#{self.class.name}:#{__id__.to_s(16)} @action=#{action} position=#{position} element=#{element.inspect}) end - def finished_b? - @action == '<' + def to_a + [ @action, @position, @element ] 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 + def self.from_a(arr) + arr = arr.flatten + case arr.size + when 5 + Diff::LCS::ContextChange.new(*(arr[0...5])) + when 3 + Diff::LCS::Change.new(*(arr[0...3])) + else + raise "Invalid change array format provided." + end + end include Comparable + def ==(other) (self.action == other.action) and (self.position == other.position) and @@ -67,85 +67,79 @@ class Diff::LCS::Change r end - def initialize(action, position, element) - @action = action - @position = position - @element = element + def adding? + @action == '+' end - # Creates a Change from an array produced by Change#to_a. - def to_a - [@action, @position, @element] + def deleting? + @action == '-' end - def self.from_a(arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) + def unchanged? + @action == '=' + end + + def changed? + @action == '!' end - include Diff::LCS::ChangeTypeTests + def finished_a? + @action == '>' + end + + def finished_b? + @action == '<' + end 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 +# 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 < Diff::LCS::Change + # We don't need these two values. + undef :position + undef :element + + # Returns the old position being changed. attr_reader :old_position - attr_reader :old_element + # Returns the new position being changed. attr_reader :new_position + # Returns the old element being changed. + attr_reader :old_element + # Returns the new element being changed. attr_reader :new_element - include Comparable + def initialize(*args) + @action, @old_position, @old_element, @new_position, @new_element = *args - 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 + unless Diff::LCS::Change.valid_action?(@action) + raise "Invalid Change Action '#{@action}'" + end + unless @old_position.nil? or @old_position.kind_of? Fixnum + raise "Invalid (Old) Position Type" + end + unless @new_position.nil? or @new_position.kind_of? Fixnum + raise "Invalid (New) Position Type" + end 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 + def to_a + [ @action, + [ @old_position, @old_element ], + [ @new_position, @new_element ] + ] end - def to_a - [@action, [@old_position, @old_element], [@new_position, @new_element]] + def inspect(*args) + %Q(#<#{self.class.name}:#{__id__} @action=#{action} positions=#{old_position},#{new_position} elements=#{old_element.inspect},#{new_element.inspect}>) 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 + Diff::LCS::Change.from_a(arr) end - # Simplifies a context change for use in some diff callbacks. '<' actions - # are converted to '-' and '>' actions are converted to '+'. + # 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 @@ -165,5 +159,20 @@ class Diff::LCS::ContextChange Diff::LCS::ContextChange.from_a(ea) end - include Diff::LCS::ChangeTypeTests + 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 <=>(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 end |