diff options
author | Austin Ziegler <austin@halostatue.ca> | 2011-07-30 19:40:23 -0400 |
---|---|---|
committer | Austin Ziegler <austin@halostatue.ca> | 2011-07-30 19:40:23 -0400 |
commit | 9feacf82a4859362662c05ffaaeaf26b40a36018 (patch) | |
tree | 57be359c74bcdabd2510835f5568b64ba61f769d | |
parent | ca444f81819ee49d3a174271dbca75061a4067f5 (diff) | |
download | diff-lcs-9feacf82a4859362662c05ffaaeaf26b40a36018.tar.gz |
Converting diff-lcs from svn to git format.
152 files changed, 0 insertions, 22788 deletions
diff --git a/diff-lcs/tags/release-1.1.2/ChangeLog b/ChangeLog index 08d3ee5..08d3ee5 100644 --- a/diff-lcs/tags/release-1.1.2/ChangeLog +++ b/ChangeLog diff --git a/diff-lcs/tags/release-1.1.2/Install b/Install index 794796e..794796e 100644 --- a/diff-lcs/tags/release-1.1.2/Install +++ b/Install diff --git a/diff-lcs/tags/release-1.1.2/README b/README index 4c9b517..4c9b517 100644 --- a/diff-lcs/tags/release-1.1.2/README +++ b/README diff --git a/diff-lcs/trunk/Rakefile b/Rakefile index e2ce55b..e2ce55b 100644 --- a/diff-lcs/trunk/Rakefile +++ b/Rakefile diff --git a/diff-lcs/tags/release-1.1.2/htmldiff b/bin/htmldiff index 509860c..509860c 100644 --- a/diff-lcs/tags/release-1.1.2/htmldiff +++ b/bin/htmldiff diff --git a/diff-lcs/tags/release-1.1.1/ldiff b/bin/ldiff index ae2b245..ae2b245 100644 --- a/diff-lcs/tags/release-1.1.1/ldiff +++ b/bin/ldiff diff --git a/diff-lcs/tags/release-1.1.2/diff-lcs.gemspec b/diff-lcs.gemspec index ba49ed6..ba49ed6 100644 --- a/diff-lcs/tags/release-1.1.2/diff-lcs.gemspec +++ b/diff-lcs.gemspec diff --git a/diff-lcs/tags/release-1.0.1/ChangeLog b/diff-lcs/tags/release-1.0.1/ChangeLog deleted file mode 100644 index a288437..0000000 --- a/diff-lcs/tags/release-1.0.1/ChangeLog +++ /dev/null @@ -1,12 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.0.1/Install b/diff-lcs/tags/release-1.0.1/Install deleted file mode 100644 index a0f2590..0000000 --- a/diff-lcs/tags/release-1.0.1/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.0.1.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.0.1/README b/diff-lcs/tags/release-1.0.1/README deleted file mode 100644 index cc4d5eb..0000000 --- a/diff-lcs/tags/release-1.0.1/README +++ /dev/null @@ -1,65 +0,0 @@ -Diff::LCS README -================ -This is the 1.0.1 release of Diff::LCS for Ruby, based originally on Perl's -Algorithm::Diff[1]. It uses the McIlroy-Hunt longest common subsequence (LCS) -algorithm to compute intelligent differences between two sequenced enumerable -containers[2]. The implementation is based on Mario I. Wolczko's[3] Smalltalk -version (1.2, 1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String -will be extended for use this way. - -Copyright -========= -#-- -# 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$ -#++ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.0.1/diff-lcs.gemspec b/diff-lcs/tags/release-1.0.1/diff-lcs.gemspec deleted file mode 100644 index 3d29622..0000000 --- a/diff-lcs/tags/release-1.0.1/diff-lcs.gemspec +++ /dev/null @@ -1,42 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.0.1} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - s.default_executable = %(ldiff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.0.1/htmldiff b/diff-lcs/tags/release-1.0.1/htmldiff deleted file mode 100644 index e013600..0000000 --- a/diff-lcs/tags/release-1.0.1/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#! /usr/bin/env 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$ -#++ - -begin - require 'diff/lcs/string' -rescue - require 'rubygems' - require_gem 'diff-lcs', "1.0.1" - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.0.1/htmldiff.bat b/diff-lcs/tags/release-1.0.1/htmldiff.bat deleted file mode 100644 index 1432736..0000000 --- a/diff-lcs/tags/release-1.0.1/htmldiff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "htmldiff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "htmldiff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0.1/install.rb b/diff-lcs/tags/release-1.0.1/install.rb deleted file mode 100644 index 0ed8e45..0000000 --- a/diff-lcs/tags/release-1.0.1/install.rb +++ /dev/null @@ -1,189 +0,0 @@ -## -# Install utility for HaloStatue scripts and libraries. Based heavily on the -# original RDoc installation script by Pragmatic Programmers. -# -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' -require 'test/unit/ui/console/testrunner' - -InstallOptions = OpenStruct.new - - # Set these values to what you want installed. -bins = %w{bin/**/*} -rdoc = %w{bin/**/*.rb lib/**/*.rb README ChangeLog Install} -ri = %w(bin/**/*.rb lib/**/*.rb) -libs = %w{lib/**/*.rb} -tests = %w{tests/**/*.rb} - -def do_bins(bins, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--no-rdoc', FalseClass, - 'Prevents the creation of RDoc output.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--no-ri', FalseClass, - 'Prevents the creation of RI output.') do |onri| - InstallOptions.ri = onri - end - opts.on('--no-tests', FalseClass, - 'Prevents the execution of nit tests.') do |ontest| - InstallOptions.tests = ontest - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers", "--show-hash"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(%w{--ri-site --line-numbers --show-hash} + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -end - -def run_tests(test_list) - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file) - tmp_dir = nil - BinDirs.each do |t| - stat = File.stat(t) rescue next - if stat.directory? and stat.writable? - tmp_dir = t - break - end - end - - fail "Cannot finda temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - opfile += ".rb" if Config::CONFIG["target_os"] =~ /win/ - FileUtils.install(tmp_file, File.join(TargetBinDir, opfile), 0755, true) - FileUtils.unlink(tmp_file) -end - -def glob(list) - g = [] - list.each { |i| g << Dir.glob(i) } - g.flatten! - g.compact! - g -end - -prepare_installation - -bins = glob(bins) -rdoc = glob(rdoc) -ri = glob(ri) -libs = glob(libs) -tests = glob(tests) - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.0.1/ldiff b/diff-lcs/tags/release-1.0.1/ldiff deleted file mode 100644 index 01bc6e4..0000000 --- a/diff-lcs/tags/release-1.0.1/ldiff +++ /dev/null @@ -1,235 +0,0 @@ -#!/user/bin/env ruby -# = Diff::LCS 1.0.1 -# == ldiff Usage -# ldiff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' - -begin - require 'diff/lcs' -rescue - require 'rubygems' - require_gem 'diff-lcs', "1.0.1" -end - -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - end - end - - output << oldhunk.diff(@format) - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -exit Diff::diffprog(ARGV, $stdout, $stderr) diff --git a/diff-lcs/tags/release-1.0.1/ldiff.bat b/diff-lcs/tags/release-1.0.1/ldiff.bat deleted file mode 100644 index ddf977f..0000000 --- a/diff-lcs/tags/release-1.0.1/ldiff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "ldiff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "ldiff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs.rb deleted file mode 100644 index e3333c4..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs.rb +++ /dev/null @@ -1,758 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.0.1 - # Computes "intelligent" differences between two ordered Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the secend sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # === Key Generation - # The Perl version accepts an optional hash-key generation code reference - # because all comparisons are done stringwise. This is not necessary for - # Ruby, as the spaceship operator (<=>) should be provided on classes that - # may be present in an ordered Enumerable. - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written by Mark-Jason Dominus - # <mjd-perl-diff@plover.com>. The basic Ruby implementation was reported - # from the Smalltalk implementation, available at - # ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # +sdiff+ and +traverse_balanced+ were written for the Perl version by - # Mike Schilli <m@perlmeister.com>. - # - # The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed. - module LCS - VERSION = '1.0.1' #:nodoc: - end -end - -require 'diff/lcs/event' -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns the Longest Common Subsequnce(s) - # LCS returns an Array containing the longest common subsequence between - # +self+ and +other+. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - def traverse_sequences(other) - traverse_sequences(self, other, Diff::LCS::YieldingCallbacks) - end - - def traverse_balanced(other) - traverse_balanced(self, other, Diff::LCS::YieldingCallbacks) - end - - def patch(diffs) - Diff::LCS::patch(self, diffs) - end -end - -module Diff::LCS - class << self - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # Compute the longest common subsequence between the ordered Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Given two ordered Enumerables, LCS returns an Array containing their - # longest common subsequence. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - def LCS(a, b, &block) #:yields self[ii] if there are matched subsequences: - matches = Diff::LCS.__lcs(a, b) - ret = [] - matches.each_with_index do |e, ii| - unless matches[ii].nil? - ret << a[ii] - yield a[ii] if block_given? - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. The description is a list of +hunks+; - # each hunk represents a contiguous section of items which should be - # added, deleted, or replaced. The return value of +diff+ is an Array - # of hunks. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # [ [ [ :-, 0, 'a' ] ], - # # [ [ :+, 2, 'd' ] ], - # # [ [ :-, 4, 'h' ], - # # [ :+, 4, 'f' ] ], - # # [ [ :+, 6, 'k' ] ], - # # [ [ :-, 8, 'n' ], - # # [ :-, 9, 'p' ], - # # [ :+, 9, 'r' ], - # # [ :+, 10, 's' ], - # # [ :+, 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at - # position 0 of the first sequence should be deleted (<tt>:-</tt>). - # The second hunk says that the +d+ at position 2 of the second - # sequence should be inserted (<tt>:+</tt>). The third hunk says that - # the +h+ at position 4 of the first sequence should be removed and - # replaced with the +f+ from position 4 of the second sequence. The - # other two hunks similarly. - def diff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::DiffCallbacks.new - traverse_sequences(a, b, callbacks) - callbacks.match(nil) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # same same - # before | after - # old < - - # - > new - # - # It returns an Array of Arrays that contain display instructions. - # Display instructions consist of three elements: A modifier indicator - # (<tt>:+</tt>: Element added, <tt>:-</tt>: Element removed, +u+: - # Element unmodified, +c+: Element changed) and the value of the old - # and new elements, to be displayed side by side. - # - # sdiffs = Diff::LCS.sdiff(seq1, seq2) - # # [ [ '-', 'a', '' ], - # # [ 'u', 'b', 'b' ], - # # [ 'u', 'c', 'c' ], - # # [ '+', '', 'd' ], - # # [ 'u', 'e', 'e' ], - # # [ 'c', 'h', 'f' ], - # # [ 'u', 'j', 'j' ], - # # [ '+', '', 'k' ], - # # [ 'u', 'l', 'l' ], - # # [ 'u', 'm', 'm' ], - # # [ 'c', 'n', 'r' ], - # # [ 'c', 'p', 's' ], - # # [ '+', '', 't' ] ] - def sdiff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::SDiffCallbacks.new - traverse_balanced(a, b, callbacks) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # Imagine that there are two arrows. Arrow A points to an element of - # sequence A, and arrow B points to an element of the sequence B. - # Initially, the arrows point to the first elements of the respective - # sequences. +traverse_sequences+ will advance the arrows through the - # sequences one element at a time, calling an appropriate - # user-specified callback function before each advance. It will - # advance the arrows in such a way that if there are equal elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt> which are equal and which are part - # of the LCS, there will be some moment during the execution of - # +traverse_sequences+ when arrow A is pointing to <tt>A[ii]</tt> and - # arrow B is pointing to <tt>B[jj]</tt>. When this happens, - # +traverse_sequences+ will call the <tt>:match</tt> lambda and then - # it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its - # sequence that is not part of the LCS. +traverse_sequences+ will - # advance that arrow and will call the <tt>:discard_a</tt> or the - # <tt>:discard_b</tt> lambdas, depending on which arrow it advanced. - # If both arrows point to elements that are not part of the LCS, then - # +traverse_sequences+ will advance one of them and call the - # appropriate callback, but it is not specified which it will call. - # - # The arguments to +traverse_sequences+ are the two sequences to - # traverse, and a hash which specifies the lambdas, like this: - # - # traverse_sequences(seq1, seq2, - # :match => callback_1, - # :discard_a => callback_2, - # :discard_b => callback_3) - # - # The lambdas for <tt>:match</tt>, <tt>:discard_a</tt>, and - # <tt>:discard_b</tt> are invoked with the indices of the two arrows - # as their arguments and are not expected to return any values. - # - # If arrow A reaches the end of its sequence before arrow B does, - # +traverse_sequences+ will call the <tt>:a_finished</tt> lambda with - # the last index in A. If <tt>:a_finished</tt> does not exist, then - # <tt>:discard_b</tt> will be called until the end of the B sequence. - # If B terminates before A, then <tt>:b_finished</tt> or - # <tt>:discard_a</tt> will be called. - # - # Omitted callbacks are not called. - # - def traverse_sequences(a, b, callbacks = Diff::LCS::SequenceCallbacks) - matches = Diff::LCS.__lcs(a, b) - - run_finished_a = run_finished_b = false - string = a.kind_of?(String) - - a_size = a.size - b_size = b.size - ai = bj = 0 - - (0 ... matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? a[ii, 1] : a[ii] - bx = string ? b[bj, 1] : b[bj] - - if b_line.nil? - event = Diff::LCS::Event.new(:discard_a, ax, ii, bx, bj) - callbacks.discard_a(event) - else - loop do - break unless bj < b_line - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ii, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:match, ax, ii, bx, bj) - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? a[-1, 1] : a[-1] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:finished_a, ax, a_size - 1, bx, bj) - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? a[ai, 1] : a[ai] - loop do - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[-1, 1] : b[-1] - event = Diff::LCS::Event.new(:finished_b, ax, ai, bx, b_size - 1) - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? b[bj, 1] : b[bj] - loop do - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - # +traverse_balanced+ is an alternative to +traverse_sequences+. It - # uses a different algorithm to iterate through the entries in the - # computed LCS. Instead of sticking to one side and showing element - # changes as insertions and deletions only, it will jump back and - # forth between the two sequences and report <em>changes</em> - # occurring as deletions on one side followed immediatly by an - # insertion on the other side. - # - # In addition to the <tt>:discard_a</tt>, <tt>:discard_b</tt>, and - # <tt>:match</tt> callbacks supported by +traverse_sequences+, - # +traverse_balanced+ supports a <tt>:change</tt> callback indicating - # that one element got +replaced+ by another: - # - # traverse_sequences(seq1, seq2, - # :match => $callback_1, - # :discard_a => $callback_2, - # :discard_b => $callback_3, - # :change => $callback_4,) - # - # If no <tt>:change</tt> callback is specified, +traverse_balanced+ - # will map <tt>:change</tt> events to <tt>:discard_a</tt> and - # <tt>:discard_b</tt> actions, therefore resulting in a similar - # behaviour as +traverse_sequences+ with different order of events. - # - # +traverse_balanced+ might be a bit slower than +traverse_sequences+, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # +traverse_balanced+. - def traverse_balanced(a, b, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(a, b) - a_size = a.size - b_size = b.size - ai = bj = mb = 0 - ma = -1 - string = a.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(s) - while (ai < ma) or (bj < mb) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - def __diff_direction(src, diffs) - left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - diffs.each do |change| - text = string ? src[change.position, 1] : src[change.position] - case change.action - when :- - if text == change.text - left += 1 - else - left_miss += 1 - end - when :+ - if text == change.text - right += 1 - else - right_miss += 1 - end - end - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided diff does not appear to apply to the provided value as either source or destination value." - end - end - - # Given a set of diffs, convert the current version to the new version. - def patch(src, diffs, direction = nil) - diffs = diffs.flatten - direction = Diff::LCS.__diff_direction(src, diffs) if direction.nil? - string = src.kind_of?(String) - - n = src.class.new - ai = bj = 0 - - uses_splat = true - - diffs.each do |change| - action = change.action - - if direction == :unpatch - case action - when :- - action = :+ - when :+ - action = :- - end - end - - case action - when :- # Delete - while ai < change.position - n << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += (change.text.kind_of?(String) ? 1 : change.text.size) - when :+ # Insert - while bj < change.position - n << (string ? src[ai, 1]: src[ai]) - ai += 1 - bj += 1 - end - - if change.text.kind_of?(String) - n << change.text - else - n.push(*change.text) - end - - bj += (change.text.kind_of?(String) ? 1 : change.text.size) - end - end - - n - end - - # Given a set of diffs, convert the current version to the prior - # version. - def unpatch(diffs) - patch(diffs, :unpatch) - end - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/array.rb deleted file mode 100644 index fea3edc..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/array.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/block.rb deleted file mode 100644 index 7ffdbab..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/block.rb +++ /dev/null @@ -1,49 +0,0 @@ -#! /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$ -#++ - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/diff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/callbacks.rb deleted file mode 100644 index eb0be60..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,99 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/change' - -class Diff::LCS::SequenceCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::BalancedCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::DiffCallbacks #:nodoc: - attr_accessor :hunk - attr_accessor :diffs - - def initialize - @hunk = [] - @diffs = [] - end - - def match(event) - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_ix, event.old_el) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_ix, event.new_el) - end -end - -class Diff::LCS::SDiffCallbacks #:nodoc: - attr_accessor :diffs - - def initialize - @diffs = [] - end - - def match(event) - @diffs << Diff::LCS::Change.new('u', event.old_el, event.new_el) - end - - def discard_a(event) - @diffs << Diff::LCS::Change.new('-', event.old_el, nil) - end - - def discard_b(event) - @diffs << Diff::LCS::Change.new('+', nil, event.new_el) - end - - def change(event) - @diffs << Diff::LCS::Change.new('!', event.old_el, event.new_el) - end -end - -class Diff::LCS::YieldingCallbacks #:nodoc: - class << self - def method_missing(symbol, *args) - yield args if block_given? - end - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/change.rb deleted file mode 100644 index a472f26..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/change.rb +++ /dev/null @@ -1,63 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Change - attr_reader :action, :position, :text - - include Comparable - - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.text == other.text) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.text <=> other.text if r.zero? - r - end - - def initialize(action, position, text) - @action = action - @position = position - @text = text - end - - def to_a - [@action, @position, @text] - end - - def self.from_a(*arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - def deleting? - @action == :- - end - - def adding? - @action == :+ - end - - def unchanged? - @action == :u - end - - def changed? - @changed == :c - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/event.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/event.rb deleted file mode 100644 index daa2414..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/event.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Event - attr_reader :code - attr_reader :old_el - attr_reader :old_ix - attr_reader :new_el - attr_reader :new_ix - - def initialize(code, a, ai, b, bi) - @code = code - @old_el = a - @old_ix = ai - @new_el = b - @new_ix = bi - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/hunk.rb deleted file mode 100644 index c57e4ba..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,256 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.0.1/lib/diff/lcs/string.rb deleted file mode 100644 index 96a01fe..0000000 --- a/diff-lcs/tags/release-1.0.1/lib/diff/lcs/string.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/array' - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.1/tests/00test.rb b/diff-lcs/tags/release-1.0.1/tests/00test.rb deleted file mode 100644 index e2613d5..0000000 --- a/diff-lcs/tags/release-1.0.1/tests/00test.rb +++ /dev/null @@ -1,431 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -if __FILE__ == $0 - class TestLCS < Test::Unit::TestCase - def setup - @a = %w(a b c e h j l m n p) - @b = %w(b c d e f j k l m r s t) - - @correct = %w(b c e j l m) - @skipped_a = "a h n p" - @skipped_b = "d f k r s t" - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '+', 9, 'r' ], - [ '-', 9, 'p' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff) - end - - def __map_diffs(diffs) - diffs.map do |chunks| - chunks.map do |changes| - Diff::LCS::Change.from_a(*changes) - end - end - end - - def __make_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_el - @matched_b << event.new_el - end - - def discard_b(event) - @discards_b << event.new_el - end - - def discard_a(event) - @discards_a << event.old_el - end - - def finished_a(event) - @done_a << [event.old_el, event.old_ix] - end - - def finished_b(event) - @done_b << [event.new_el, event.new_ix] - end - end - callbacks.reset - callbacks - end - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@a, @b) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct.size) - assert_nothing_raised { ares = (0...res.size).map { |i| res[i] ? @a[i] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |i| res[i] ? @b[res[i]] : nil } } - assert_equal(@correct, ares.compact) - assert_equal(@correct, bres.compact) - end - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __make_callbacks - class << callbacks - undef finished_a - undef finished_b - end - end - assert_nothing_raised { Diff::LCS.traverse_sequences(@a, @b, callbacks) } - assert_equal(@correct.size, callbacks.matched_a.size) - assert_equal(@correct.size, callbacks.matched_b.size) - assert_equal(@skipped_a, callbacks.discards_a.join(" ")) - assert_equal(@skipped_b, callbacks.discards_b.join(" ")) - assert_nothing_raised { callbacks = __make_callbacks } - assert_nothing_raised { Diff::LCS.traverse_sequences(@a, @b, callbacks) } - assert_equal(@correct.size, callbacks.matched_a.size) - assert_equal(@correct.size, callbacks.matched_b.size) - assert_equal(@skipped_a, callbacks.discards_a.join(" ")) - assert_equal(@skipped_b, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - end - - def test_LCS - res = nil - assert_nothing_raised { res = Diff::LCS.LCS(@a, @b) } - assert_equal(res.compact, @correct) - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@a, @b) } - assert_equal(@correct_diff, diff) - end - - def test_sdiff_a - sdiff = nil - a = %w(abc def yyy xxx ghi jkl) - b = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - ['u', 'abc', 'abc'], - ['!', 'def', 'dxf'], - ['-', 'yyy', nil], - ['u', 'xxx', 'xxx'], - ['u', 'ghi', 'ghi'], - ['u', 'jkl', 'jkl'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - ['-', 'a', nil], - ['u', 'b', 'b'], - ['u', 'c', 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'], - ['!', 'h', 'f'], - ['u', 'j', 'j'], - ['+', nil, 'k'], - ['u', 'l', 'l'], - ['u', 'm', 'm'], - ['!', 'n', 'r'], - ['!', 'p', 's'], - ['+', nil, 't'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@a, @b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - a = %w(a b c d e) - b = %w(a e) - correct_sdiff = [ - ['u', 'a', 'a' ], - ['-', 'b', nil ], - ['-', 'c', nil ], - ['-', 'd', nil ], - ['u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - a = %w(a e) - b = %w(a b c d e) - correct_sdiff = [ - ['u', 'a', 'a' ], - ['+', nil, 'b' ], - ['+', nil, 'c' ], - ['+', nil, 'd' ], - ['u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - a = %w(v x a e) - b = %w(w y a b c d e) - correct_sdiff = [ - ['!', 'v', 'w' ], - ['!', 'x', 'y' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - a = %w(x a e) - b = %w(a b c d e) - correct_sdiff = [ - ['-', 'x', nil ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - a = %w(a e) - b = %w(x a b c d e) - correct_sdiff = [ - ['+', nil, 'x' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - a = %w(a e v) - b = %w(x a b c d e w x) - correct_sdiff = [ - ['+', nil, 'x' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'], - ['!', 'v', 'w'], - ['+', nil, 'x'] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - a = %w() - b = %w(a b c) - correct_sdiff = [ - ['+', nil, 'a' ], - ['+', nil, 'b' ], - ['+', nil, 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - a = %w(a b c) - b = %w() - correct_sdiff = [ - ['-', 'a', nil ], - ['-', 'b', nil ], - ['-', 'c', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - a = %w(a b c) - b = %w(1) - correct_sdiff = [ - ['!', 'a', '1' ], - ['-', 'b', nil ], - ['-', 'c', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - a = %w(a b c) - b = %w(c) - correct_sdiff = [ - ['-', 'a', nil ], - ['-', 'b', nil ], - ['u', 'c', 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M #{event.old_ix} #{event.new_ix}" - end - - def discard_a(event) - @result << "DA #{event.old_ix} #{event.new_ix}" - end - - def discard_b(event) - @result << "DB #{event.old_ix} #{event.new_ix}" - end - - def change(event) - @result << "C #{event.old_ix} #{event.new_ix}" - end - end - cb.reset - cb - end - - def test_balanced_a - a = %w(a b c) - b = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0C 1 1M 2 2", callback.result) - end - - def test_balanced_b - a = %w(a b c) - b = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0DA 1 1DB 2 1M 2 2", callback.result) - end - - def test_balanced_c - a = %w(a x y c) - b = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0C 1 1C 2 2M 3 3", callback.result) - end - - def test_balanced_d - a = %w(x y c) - b = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1M 2 2", callback.result) - end - - def test_balanced_e - a = %w(a x y z) - b = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1C 2 2DA 3 3", callback.result) - end - - def test_balanced_f - a = %w(a z) - b = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0DA 1 1", callback.result) - end - - def test_balanced_g - a = %w(z a) - b = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("DA 0 0M 1 0", callback.result) - end - - def test_balanced_h - a = %w(a b c) - b = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1C 2 2", callback.result) - end - end -end diff --git a/diff-lcs/tags/release-1.0.2/ChangeLog b/diff-lcs/tags/release-1.0.2/ChangeLog deleted file mode 100644 index 75a392e..0000000 --- a/diff-lcs/tags/release-1.0.2/ChangeLog +++ /dev/null @@ -1,26 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.0.2/Install b/diff-lcs/tags/release-1.0.2/Install deleted file mode 100644 index b583d3f..0000000 --- a/diff-lcs/tags/release-1.0.2/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.0.4.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.0.2/README b/diff-lcs/tags/release-1.0.2/README deleted file mode 100644 index a7021e7..0000000 --- a/diff-lcs/tags/release-1.0.2/README +++ /dev/null @@ -1,66 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.0.4. It contains only bug fixes over 1.0.2 and -1.0.3. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.0.2/diff-lcs.gemspec b/diff-lcs/tags/release-1.0.2/diff-lcs.gemspec deleted file mode 100644 index 93ca917..0000000 --- a/diff-lcs/tags/release-1.0.2/diff-lcs.gemspec +++ /dev/null @@ -1,42 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.0.4} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - s.default_executable = %(ldiff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.0.2/htmldiff b/diff-lcs/tags/release-1.0.2/htmldiff deleted file mode 100644 index ef41888..0000000 --- a/diff-lcs/tags/release-1.0.2/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env 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$ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.0.4" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.0.2/install.rb b/diff-lcs/tags/release-1.0.2/install.rb deleted file mode 100644 index 5772e0b..0000000 --- a/diff-lcs/tags/release-1.0.2/install.rb +++ /dev/null @@ -1,264 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.0.2/ldiff b/diff-lcs/tags/release-1.0.2/ldiff deleted file mode 100644 index a60a19d..0000000 --- a/diff-lcs/tags/release-1.0.2/ldiff +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env ruby -# = Diff::LCS 1.0.4 -# == ldiff Usage -# ldiff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.0.4" -rescue LoadError - require 'diff/lcs' -end - -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -exit Diff::diffprog(ARGV, $stdout, $stderr) diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs.rb deleted file mode 100644 index ad3c1c2..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs.rb +++ /dev/null @@ -1,760 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.0.4 - # Computes "intelligent" differences between two ordered Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the secend sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # === Key Generation - # The Perl version accepts an optional hash-key generation code reference - # because all comparisons are done stringwise. This is not necessary for - # Ruby, as the spaceship operator (<=>) should be provided on classes that - # may be present in an ordered Enumerable. - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written by Mark-Jason Dominus - # <mjd-perl-diff@plover.com>. The basic Ruby implementation was reported - # from the Smalltalk implementation, available at - # ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # +sdiff+ and +traverse_balanced+ were written for the Perl version by - # Mike Schilli <m@perlmeister.com>. - # - # The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed. - module LCS - VERSION = '1.0.4' #:nodoc: - end -end - -require 'diff/lcs/event' -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns the Longest Common Subsequnce(s) - # LCS returns an Array containing the longest common subsequence between - # +self+ and +other+. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - def traverse_sequences(other) - traverse_sequences(self, other, Diff::LCS::YieldingCallbacks) - end - - def traverse_balanced(other) - traverse_balanced(self, other, Diff::LCS::YieldingCallbacks) - end - - def patch(diffs) - Diff::LCS::patch(self, diffs) - end -end - -module Diff::LCS - class << self - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # Compute the longest common subsequence between the ordered Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Given two ordered Enumerables, LCS returns an Array containing their - # longest common subsequence. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - def LCS(a, b, &block) #:yields self[ii] if there are matched subsequences: - matches = Diff::LCS.__lcs(a, b) - ret = [] - matches.each_with_index do |e, ii| - unless matches[ii].nil? - ret << a[ii] - yield a[ii] if block_given? - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. The description is a list of +hunks+; - # each hunk represents a contiguous section of items which should be - # added, deleted, or replaced. The return value of +diff+ is an Array - # of hunks. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # [ [ [ :-, 0, 'a' ] ], - # # [ [ :+, 2, 'd' ] ], - # # [ [ :-, 4, 'h' ], - # # [ :+, 4, 'f' ] ], - # # [ [ :+, 6, 'k' ] ], - # # [ [ :-, 8, 'n' ], - # # [ :-, 9, 'p' ], - # # [ :+, 9, 'r' ], - # # [ :+, 10, 's' ], - # # [ :+, 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at - # position 0 of the first sequence should be deleted (<tt>:-</tt>). - # The second hunk says that the +d+ at position 2 of the second - # sequence should be inserted (<tt>:+</tt>). The third hunk says that - # the +h+ at position 4 of the first sequence should be removed and - # replaced with the +f+ from position 4 of the second sequence. The - # other two hunks similarly. - def diff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::DiffCallbacks.new - traverse_sequences(a, b, callbacks) - callbacks.match(nil) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # same same - # before | after - # old < - - # - > new - # - # It returns an Array of Arrays that contain display instructions. - # Display instructions consist of three elements: A modifier indicator - # (<tt>:+</tt>: Element added, <tt>:-</tt>: Element removed, +u+: - # Element unmodified, +c+: Element changed) and the value of the old - # and new elements, to be displayed side by side. - # - # sdiffs = Diff::LCS.sdiff(seq1, seq2) - # # [ [ '-', 'a', '' ], - # # [ 'u', 'b', 'b' ], - # # [ 'u', 'c', 'c' ], - # # [ '+', '', 'd' ], - # # [ 'u', 'e', 'e' ], - # # [ 'c', 'h', 'f' ], - # # [ 'u', 'j', 'j' ], - # # [ '+', '', 'k' ], - # # [ 'u', 'l', 'l' ], - # # [ 'u', 'm', 'm' ], - # # [ 'c', 'n', 'r' ], - # # [ 'c', 'p', 's' ], - # # [ '+', '', 't' ] ] - def sdiff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::SDiffCallbacks.new - traverse_balanced(a, b, callbacks) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # Imagine that there are two arrows. Arrow A points to an element of - # sequence A, and arrow B points to an element of the sequence B. - # Initially, the arrows point to the first elements of the respective - # sequences. +traverse_sequences+ will advance the arrows through the - # sequences one element at a time, calling an appropriate - # user-specified callback function before each advance. It will - # advance the arrows in such a way that if there are equal elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt> which are equal and which are part - # of the LCS, there will be some moment during the execution of - # +traverse_sequences+ when arrow A is pointing to <tt>A[ii]</tt> and - # arrow B is pointing to <tt>B[jj]</tt>. When this happens, - # +traverse_sequences+ will call the <tt>:match</tt> lambda and then - # it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its - # sequence that is not part of the LCS. +traverse_sequences+ will - # advance that arrow and will call the <tt>:discard_a</tt> or the - # <tt>:discard_b</tt> lambdas, depending on which arrow it advanced. - # If both arrows point to elements that are not part of the LCS, then - # +traverse_sequences+ will advance one of them and call the - # appropriate callback, but it is not specified which it will call. - # - # The arguments to +traverse_sequences+ are the two sequences to - # traverse, and a hash which specifies the lambdas, like this: - # - # traverse_sequences(seq1, seq2, - # :match => callback_1, - # :discard_a => callback_2, - # :discard_b => callback_3) - # - # The lambdas for <tt>:match</tt>, <tt>:discard_a</tt>, and - # <tt>:discard_b</tt> are invoked with the indices of the two arrows - # as their arguments and are not expected to return any values. - # - # If arrow A reaches the end of its sequence before arrow B does, - # +traverse_sequences+ will call the <tt>:a_finished</tt> lambda with - # the last index in A. If <tt>:a_finished</tt> does not exist, then - # <tt>:discard_b</tt> will be called until the end of the B sequence. - # If B terminates before A, then <tt>:b_finished</tt> or - # <tt>:discard_a</tt> will be called. - # - # Omitted callbacks are not called. - # - def traverse_sequences(a, b, callbacks = Diff::LCS::SequenceCallbacks) - matches = Diff::LCS.__lcs(a, b) - - run_finished_a = run_finished_b = false - string = a.kind_of?(String) - - a_size = a.size - b_size = b.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? a[ii, 1] : a[ii] - bx = string ? b[bj, 1] : b[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::Event.new(:discard_a, ax, ii, bx, bj) - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ii, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:match, ax, ii, bx, bj) - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? a[-1, 1] : a[-1] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:finished_a, ax, a_size - 1, bx, bj) - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? a[ai, 1] : a[ai] - loop do - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[-1, 1] : b[-1] - event = Diff::LCS::Event.new(:finished_b, ax, ai, bx, b_size - 1) - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? b[bj, 1] : b[bj] - loop do - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - # +traverse_balanced+ is an alternative to +traverse_sequences+. It - # uses a different algorithm to iterate through the entries in the - # computed LCS. Instead of sticking to one side and showing element - # changes as insertions and deletions only, it will jump back and - # forth between the two sequences and report <em>changes</em> - # occurring as deletions on one side followed immediatly by an - # insertion on the other side. - # - # In addition to the <tt>:discard_a</tt>, <tt>:discard_b</tt>, and - # <tt>:match</tt> callbacks supported by +traverse_sequences+, - # +traverse_balanced+ supports a <tt>:change</tt> callback indicating - # that one element got +replaced+ by another: - # - # traverse_sequences(seq1, seq2, - # :match => $callback_1, - # :discard_a => $callback_2, - # :discard_b => $callback_3, - # :change => $callback_4,) - # - # If no <tt>:change</tt> callback is specified, +traverse_balanced+ - # will map <tt>:change</tt> events to <tt>:discard_a</tt> and - # <tt>:discard_b</tt> actions, therefore resulting in a similar - # behaviour as +traverse_sequences+ with different order of events. - # - # +traverse_balanced+ might be a bit slower than +traverse_sequences+, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # +traverse_balanced+. - def traverse_balanced(a, b, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(a, b) - a_size = a.size - b_size = b.size - ai = bj = mb = 0 - ma = -1 - string = a.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(s) - while (ai < ma) or (bj < mb) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - def __diff_direction(src, diffs) - left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - diffs.each do |change| - text = string ? src[change.position, 1] : src[change.position] - case change.action - when :- - if text == change.text - left += 1 - else - left_miss += 1 - end - when :+ - if text == change.text - right += 1 - else - right_miss += 1 - end - end - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided diff does not appear to apply to the provided value as either source or destination value." - end - end - - # Given a set of diffs, convert the current version to the new version. - def patch(src, diffs, direction = nil) - diffs = diffs.flatten - direction = Diff::LCS.__diff_direction(src, diffs) if direction.nil? - string = src.kind_of?(String) - - n = src.class.new - ai = bj = 0 - - uses_splat = true - - diffs.each do |change| - action = change.action - - if direction == :unpatch - case action - when :- - action = :+ - when :+ - action = :- - end - end - - case action - when :- # Delete - while ai < change.position - n << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += (change.text.kind_of?(String) ? 1 : change.text.size) - when :+ # Insert - while bj < change.position - n << (string ? src[ai, 1]: src[ai]) - ai += 1 - bj += 1 - end - - if change.text.kind_of?(String) - n << change.text - else - n.push(*change.text) - end - - bj += (change.text.kind_of?(String) ? 1 : change.text.size) - end - end - - n - end - - # Given a set of diffs, convert the current version to the prior - # version. - def unpatch(diffs) - patch(diffs, :unpatch) - end - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/array.rb deleted file mode 100644 index fea3edc..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/array.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/block.rb deleted file mode 100644 index 7ffdbab..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/block.rb +++ /dev/null @@ -1,49 +0,0 @@ -#! /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$ -#++ - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/diff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/callbacks.rb deleted file mode 100644 index eb0be60..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,99 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/change' - -class Diff::LCS::SequenceCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::BalancedCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::DiffCallbacks #:nodoc: - attr_accessor :hunk - attr_accessor :diffs - - def initialize - @hunk = [] - @diffs = [] - end - - def match(event) - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_ix, event.old_el) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_ix, event.new_el) - end -end - -class Diff::LCS::SDiffCallbacks #:nodoc: - attr_accessor :diffs - - def initialize - @diffs = [] - end - - def match(event) - @diffs << Diff::LCS::Change.new('u', event.old_el, event.new_el) - end - - def discard_a(event) - @diffs << Diff::LCS::Change.new('-', event.old_el, nil) - end - - def discard_b(event) - @diffs << Diff::LCS::Change.new('+', nil, event.new_el) - end - - def change(event) - @diffs << Diff::LCS::Change.new('!', event.old_el, event.new_el) - end -end - -class Diff::LCS::YieldingCallbacks #:nodoc: - class << self - def method_missing(symbol, *args) - yield args if block_given? - end - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/change.rb deleted file mode 100644 index ae5e904..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/change.rb +++ /dev/null @@ -1,63 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Change - attr_reader :action, :position, :text - - include Comparable - - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.text == other.text) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.text <=> other.text if r.zero? - r - end - - def initialize(action, position, text) - @action = action - @position = position - @text = text - end - - def to_a - [@action, @position, @text] - end - - def self.from_a(*arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - def deleting? - @action == '-' - end - - def adding? - @action == '+' - end - - def unchanged? - @action == 'u' - end - - def changed? - @changed == 'c' - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/event.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/event.rb deleted file mode 100644 index daa2414..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/event.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Event - attr_reader :code - attr_reader :old_el - attr_reader :old_ix - attr_reader :new_el - attr_reader :new_ix - - def initialize(code, a, ai, b, bi) - @code = code - @old_el = a - @old_ix = ai - @new_el = b - @new_ix = bi - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/hunk.rb deleted file mode 100644 index c57e4ba..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,256 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.0.2/lib/diff/lcs/string.rb deleted file mode 100644 index 96a01fe..0000000 --- a/diff-lcs/tags/release-1.0.2/lib/diff/lcs/string.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/array' - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.2/tests/00test.rb b/diff-lcs/tags/release-1.0.2/tests/00test.rb deleted file mode 100644 index ef8c945..0000000 --- a/diff-lcs/tags/release-1.0.2/tests/00test.rb +++ /dev/null @@ -1,525 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::Change) - diffs.map do |chunks| - chunks.map { |changes| klass.from_a(*changes) } - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_el - @matched_b << event.new_el - end - - def discard_b(event) - @discards_b << event.new_el - end - - def discard_a(event) - @discards_a << event.old_el - end - - def finished_a(event) - @done_a << [event.old_el, event.old_ix] - end - - def finished_b(event) - @done_b << [event.new_el, event.new_ix] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_ix}#{event.new_ix} " - end - - def discard_a(event) - @result << "DA#{event.old_ix}#{event.new_ix} " - end - - def discard_b(event) - @result << "DB#{event.old_ix}#{event.new_ix} " - end - - def change(event) - @result << "C#{event.old_ix}#{event.new_ix} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ 'u', 'abc', 'abc' ], - [ '!', 'def', 'dxf' ], - [ '-', 'yyy', nil ], - [ 'u', 'xxx', 'xxx' ], - [ 'u', 'ghi', 'ghi' ], - [ 'u', 'jkl', 'jkl' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', 'a', nil ], - [ 'u', 'b', 'b' ], - [ 'u', 'c', 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'h', 'f' ], - [ 'u', 'j', 'j' ], - [ '+', nil, 'k' ], - [ 'u', 'l', 'l' ], - [ 'u', 'm', 'm' ], - [ '!', 'n', 'r' ], - [ '!', 'p', 's' ], - [ '+', nil, 't' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ], - [ '-', 'd', nil ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', 'v', 'w' ], - [ '!', 'x', 'y' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', 'x', nil ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'v', 'w' ], - [ '+', nil, 'x' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', nil, 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', 'a', '1' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ 'u', 'c', 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', 'abcd', nil ], - [ '-', 'efgh', nil ], - [ '-', 'ijkl', nil ], - [ '-', 'mnop', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', nil, 'abcd' ], - [ '+', nil, 'efgh' ], - [ '+', nil, 'ijkl' ], - [ '+', nil, 'mnop' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end diff --git a/diff-lcs/tags/release-1.0.3/ChangeLog b/diff-lcs/tags/release-1.0.3/ChangeLog deleted file mode 100644 index eeccc3b..0000000 --- a/diff-lcs/tags/release-1.0.3/ChangeLog +++ /dev/null @@ -1,20 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.0.3/Install b/diff-lcs/tags/release-1.0.3/Install deleted file mode 100644 index 681b189..0000000 --- a/diff-lcs/tags/release-1.0.3/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.0.3.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.0.3/README b/diff-lcs/tags/release-1.0.3/README deleted file mode 100644 index 8585fe3..0000000 --- a/diff-lcs/tags/release-1.0.3/README +++ /dev/null @@ -1,65 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt longest -common subsequence (LCS) algorithm to compute intelligent differences between -two sequenced enumerable containers[2]. The implementation is based on Mario I. -Wolczko's[3] Smalltalk version (1.2, 1993)[4] and Ned Konz's[5] Perl version -(Algorithm::Diff)[6]. - -This release is version 1.0.3. It contains only bug fixes over 1.0.2. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will be -extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.0.3/diff-lcs.gemspec b/diff-lcs/tags/release-1.0.3/diff-lcs.gemspec deleted file mode 100644 index edf3535..0000000 --- a/diff-lcs/tags/release-1.0.3/diff-lcs.gemspec +++ /dev/null @@ -1,42 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.0.3} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - s.default_executable = %(ldiff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.0.3/htmldiff b/diff-lcs/tags/release-1.0.3/htmldiff deleted file mode 100644 index 9ef34a4..0000000 --- a/diff-lcs/tags/release-1.0.3/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#! /usr/bin/env 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$ -#++ - -begin - require 'diff/lcs/string' -rescue - require 'rubygems' - require_gem 'diff-lcs', "1.0.3" - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.0.3/htmldiff.bat b/diff-lcs/tags/release-1.0.3/htmldiff.bat deleted file mode 100644 index 1432736..0000000 --- a/diff-lcs/tags/release-1.0.3/htmldiff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "htmldiff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "htmldiff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0.3/install.rb b/diff-lcs/tags/release-1.0.3/install.rb deleted file mode 100644 index 2b85c59..0000000 --- a/diff-lcs/tags/release-1.0.3/install.rb +++ /dev/null @@ -1,206 +0,0 @@ -## -# Install utility for HaloStatue scripts and libraries. Based heavily on the -# original RDoc installation script by Pragmatic Programmers. -# -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' -require 'test/unit/ui/console/testrunner' - -InstallOptions = OpenStruct.new - -def glob(list) - g = [] - list.each { |i| g << Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--no-rdoc', FalseClass, - 'Prevents the creation of RDoc output.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', - 'Prevents the creation of RI output.', - 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--no-tests', FalseClass, - 'Prevents the execution of unit tests.') do |ontest| - InstallOptions.tests = ontest - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers", "--show-hash"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(%w{--ri-site --show-hash} + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/i - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - op_file += ".rb" if not installed_wrapper - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.0.3/ldiff b/diff-lcs/tags/release-1.0.3/ldiff deleted file mode 100644 index 047e022..0000000 --- a/diff-lcs/tags/release-1.0.3/ldiff +++ /dev/null @@ -1,235 +0,0 @@ -#!/user/bin/env ruby -# = Diff::LCS 1.0.3 -# == ldiff Usage -# ldiff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' - -begin - require 'diff/lcs' -rescue - require 'rubygems' - require_gem 'diff-lcs', "1.0.3" -end - -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - end - end - - output << oldhunk.diff(@format) - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -exit Diff::diffprog(ARGV, $stdout, $stderr) diff --git a/diff-lcs/tags/release-1.0.3/ldiff.bat b/diff-lcs/tags/release-1.0.3/ldiff.bat deleted file mode 100644 index ddf977f..0000000 --- a/diff-lcs/tags/release-1.0.3/ldiff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "ldiff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "ldiff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs.rb deleted file mode 100644 index 6489a21..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs.rb +++ /dev/null @@ -1,760 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.0.3 - # Computes "intelligent" differences between two ordered Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the secend sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # === Key Generation - # The Perl version accepts an optional hash-key generation code reference - # because all comparisons are done stringwise. This is not necessary for - # Ruby, as the spaceship operator (<=>) should be provided on classes that - # may be present in an ordered Enumerable. - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written by Mark-Jason Dominus - # <mjd-perl-diff@plover.com>. The basic Ruby implementation was reported - # from the Smalltalk implementation, available at - # ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # +sdiff+ and +traverse_balanced+ were written for the Perl version by - # Mike Schilli <m@perlmeister.com>. - # - # The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed. - module LCS - VERSION = '1.0.3' #:nodoc: - end -end - -require 'diff/lcs/event' -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns the Longest Common Subsequnce(s) - # LCS returns an Array containing the longest common subsequence between - # +self+ and +other+. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - def traverse_sequences(other) - traverse_sequences(self, other, Diff::LCS::YieldingCallbacks) - end - - def traverse_balanced(other) - traverse_balanced(self, other, Diff::LCS::YieldingCallbacks) - end - - def patch(diffs) - Diff::LCS::patch(self, diffs) - end -end - -module Diff::LCS - class << self - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # Compute the longest common subsequence between the ordered Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Given two ordered Enumerables, LCS returns an Array containing their - # longest common subsequence. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - def LCS(a, b, &block) #:yields self[ii] if there are matched subsequences: - matches = Diff::LCS.__lcs(a, b) - ret = [] - matches.each_with_index do |e, ii| - unless matches[ii].nil? - ret << a[ii] - yield a[ii] if block_given? - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. The description is a list of +hunks+; - # each hunk represents a contiguous section of items which should be - # added, deleted, or replaced. The return value of +diff+ is an Array - # of hunks. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # [ [ [ :-, 0, 'a' ] ], - # # [ [ :+, 2, 'd' ] ], - # # [ [ :-, 4, 'h' ], - # # [ :+, 4, 'f' ] ], - # # [ [ :+, 6, 'k' ] ], - # # [ [ :-, 8, 'n' ], - # # [ :-, 9, 'p' ], - # # [ :+, 9, 'r' ], - # # [ :+, 10, 's' ], - # # [ :+, 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at - # position 0 of the first sequence should be deleted (<tt>:-</tt>). - # The second hunk says that the +d+ at position 2 of the second - # sequence should be inserted (<tt>:+</tt>). The third hunk says that - # the +h+ at position 4 of the first sequence should be removed and - # replaced with the +f+ from position 4 of the second sequence. The - # other two hunks similarly. - def diff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::DiffCallbacks.new - traverse_sequences(a, b, callbacks) - callbacks.match(nil) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # same same - # before | after - # old < - - # - > new - # - # It returns an Array of Arrays that contain display instructions. - # Display instructions consist of three elements: A modifier indicator - # (<tt>:+</tt>: Element added, <tt>:-</tt>: Element removed, +u+: - # Element unmodified, +c+: Element changed) and the value of the old - # and new elements, to be displayed side by side. - # - # sdiffs = Diff::LCS.sdiff(seq1, seq2) - # # [ [ '-', 'a', '' ], - # # [ 'u', 'b', 'b' ], - # # [ 'u', 'c', 'c' ], - # # [ '+', '', 'd' ], - # # [ 'u', 'e', 'e' ], - # # [ 'c', 'h', 'f' ], - # # [ 'u', 'j', 'j' ], - # # [ '+', '', 'k' ], - # # [ 'u', 'l', 'l' ], - # # [ 'u', 'm', 'm' ], - # # [ 'c', 'n', 'r' ], - # # [ 'c', 'p', 's' ], - # # [ '+', '', 't' ] ] - def sdiff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::SDiffCallbacks.new - traverse_balanced(a, b, callbacks) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # Imagine that there are two arrows. Arrow A points to an element of - # sequence A, and arrow B points to an element of the sequence B. - # Initially, the arrows point to the first elements of the respective - # sequences. +traverse_sequences+ will advance the arrows through the - # sequences one element at a time, calling an appropriate - # user-specified callback function before each advance. It will - # advance the arrows in such a way that if there are equal elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt> which are equal and which are part - # of the LCS, there will be some moment during the execution of - # +traverse_sequences+ when arrow A is pointing to <tt>A[ii]</tt> and - # arrow B is pointing to <tt>B[jj]</tt>. When this happens, - # +traverse_sequences+ will call the <tt>:match</tt> lambda and then - # it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its - # sequence that is not part of the LCS. +traverse_sequences+ will - # advance that arrow and will call the <tt>:discard_a</tt> or the - # <tt>:discard_b</tt> lambdas, depending on which arrow it advanced. - # If both arrows point to elements that are not part of the LCS, then - # +traverse_sequences+ will advance one of them and call the - # appropriate callback, but it is not specified which it will call. - # - # The arguments to +traverse_sequences+ are the two sequences to - # traverse, and a hash which specifies the lambdas, like this: - # - # traverse_sequences(seq1, seq2, - # :match => callback_1, - # :discard_a => callback_2, - # :discard_b => callback_3) - # - # The lambdas for <tt>:match</tt>, <tt>:discard_a</tt>, and - # <tt>:discard_b</tt> are invoked with the indices of the two arrows - # as their arguments and are not expected to return any values. - # - # If arrow A reaches the end of its sequence before arrow B does, - # +traverse_sequences+ will call the <tt>:a_finished</tt> lambda with - # the last index in A. If <tt>:a_finished</tt> does not exist, then - # <tt>:discard_b</tt> will be called until the end of the B sequence. - # If B terminates before A, then <tt>:b_finished</tt> or - # <tt>:discard_a</tt> will be called. - # - # Omitted callbacks are not called. - # - def traverse_sequences(a, b, callbacks = Diff::LCS::SequenceCallbacks) - matches = Diff::LCS.__lcs(a, b) - - run_finished_a = run_finished_b = false - string = a.kind_of?(String) - - a_size = a.size - b_size = b.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? a[ii, 1] : a[ii] - bx = string ? b[bj, 1] : b[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::Event.new(:discard_a, ax, ii, bx, bj) - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ii, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:match, ax, ii, bx, bj) - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? a[-1, 1] : a[-1] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:finished_a, ax, a_size - 1, bx, bj) - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? a[ai, 1] : a[ai] - loop do - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[-1, 1] : b[-1] - event = Diff::LCS::Event.new(:finished_b, ax, ai, bx, b_size - 1) - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? b[bj, 1] : b[bj] - loop do - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - # +traverse_balanced+ is an alternative to +traverse_sequences+. It - # uses a different algorithm to iterate through the entries in the - # computed LCS. Instead of sticking to one side and showing element - # changes as insertions and deletions only, it will jump back and - # forth between the two sequences and report <em>changes</em> - # occurring as deletions on one side followed immediatly by an - # insertion on the other side. - # - # In addition to the <tt>:discard_a</tt>, <tt>:discard_b</tt>, and - # <tt>:match</tt> callbacks supported by +traverse_sequences+, - # +traverse_balanced+ supports a <tt>:change</tt> callback indicating - # that one element got +replaced+ by another: - # - # traverse_sequences(seq1, seq2, - # :match => $callback_1, - # :discard_a => $callback_2, - # :discard_b => $callback_3, - # :change => $callback_4,) - # - # If no <tt>:change</tt> callback is specified, +traverse_balanced+ - # will map <tt>:change</tt> events to <tt>:discard_a</tt> and - # <tt>:discard_b</tt> actions, therefore resulting in a similar - # behaviour as +traverse_sequences+ with different order of events. - # - # +traverse_balanced+ might be a bit slower than +traverse_sequences+, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # +traverse_balanced+. - def traverse_balanced(a, b, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(a, b) - a_size = a.size - b_size = b.size - ai = bj = mb = 0 - ma = -1 - string = a.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(s) - while (ai < ma) or (bj < mb) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - def __diff_direction(src, diffs) - left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - diffs.each do |change| - text = string ? src[change.position, 1] : src[change.position] - case change.action - when :- - if text == change.text - left += 1 - else - left_miss += 1 - end - when :+ - if text == change.text - right += 1 - else - right_miss += 1 - end - end - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided diff does not appear to apply to the provided value as either source or destination value." - end - end - - # Given a set of diffs, convert the current version to the new version. - def patch(src, diffs, direction = nil) - diffs = diffs.flatten - direction = Diff::LCS.__diff_direction(src, diffs) if direction.nil? - string = src.kind_of?(String) - - n = src.class.new - ai = bj = 0 - - uses_splat = true - - diffs.each do |change| - action = change.action - - if direction == :unpatch - case action - when :- - action = :+ - when :+ - action = :- - end - end - - case action - when :- # Delete - while ai < change.position - n << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += (change.text.kind_of?(String) ? 1 : change.text.size) - when :+ # Insert - while bj < change.position - n << (string ? src[ai, 1]: src[ai]) - ai += 1 - bj += 1 - end - - if change.text.kind_of?(String) - n << change.text - else - n.push(*change.text) - end - - bj += (change.text.kind_of?(String) ? 1 : change.text.size) - end - end - - n - end - - # Given a set of diffs, convert the current version to the prior - # version. - def unpatch(diffs) - patch(diffs, :unpatch) - end - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/array.rb deleted file mode 100644 index fea3edc..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/array.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/block.rb deleted file mode 100644 index 7ffdbab..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/block.rb +++ /dev/null @@ -1,49 +0,0 @@ -#! /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$ -#++ - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/diff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/callbacks.rb deleted file mode 100644 index eb0be60..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,99 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/change' - -class Diff::LCS::SequenceCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::BalancedCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::DiffCallbacks #:nodoc: - attr_accessor :hunk - attr_accessor :diffs - - def initialize - @hunk = [] - @diffs = [] - end - - def match(event) - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_ix, event.old_el) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_ix, event.new_el) - end -end - -class Diff::LCS::SDiffCallbacks #:nodoc: - attr_accessor :diffs - - def initialize - @diffs = [] - end - - def match(event) - @diffs << Diff::LCS::Change.new('u', event.old_el, event.new_el) - end - - def discard_a(event) - @diffs << Diff::LCS::Change.new('-', event.old_el, nil) - end - - def discard_b(event) - @diffs << Diff::LCS::Change.new('+', nil, event.new_el) - end - - def change(event) - @diffs << Diff::LCS::Change.new('!', event.old_el, event.new_el) - end -end - -class Diff::LCS::YieldingCallbacks #:nodoc: - class << self - def method_missing(symbol, *args) - yield args if block_given? - end - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/change.rb deleted file mode 100644 index ae5e904..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/change.rb +++ /dev/null @@ -1,63 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Change - attr_reader :action, :position, :text - - include Comparable - - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.text == other.text) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.text <=> other.text if r.zero? - r - end - - def initialize(action, position, text) - @action = action - @position = position - @text = text - end - - def to_a - [@action, @position, @text] - end - - def self.from_a(*arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - def deleting? - @action == '-' - end - - def adding? - @action == '+' - end - - def unchanged? - @action == 'u' - end - - def changed? - @changed == 'c' - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/event.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/event.rb deleted file mode 100644 index daa2414..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/event.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Event - attr_reader :code - attr_reader :old_el - attr_reader :old_ix - attr_reader :new_el - attr_reader :new_ix - - def initialize(code, a, ai, b, bi) - @code = code - @old_el = a - @old_ix = ai - @new_el = b - @new_ix = bi - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/hunk.rb deleted file mode 100644 index c57e4ba..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,256 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.0.3/lib/diff/lcs/string.rb deleted file mode 100644 index 96a01fe..0000000 --- a/diff-lcs/tags/release-1.0.3/lib/diff/lcs/string.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/array' - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.3/tests/00test.rb b/diff-lcs/tags/release-1.0.3/tests/00test.rb deleted file mode 100644 index ef8c945..0000000 --- a/diff-lcs/tags/release-1.0.3/tests/00test.rb +++ /dev/null @@ -1,525 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::Change) - diffs.map do |chunks| - chunks.map { |changes| klass.from_a(*changes) } - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_el - @matched_b << event.new_el - end - - def discard_b(event) - @discards_b << event.new_el - end - - def discard_a(event) - @discards_a << event.old_el - end - - def finished_a(event) - @done_a << [event.old_el, event.old_ix] - end - - def finished_b(event) - @done_b << [event.new_el, event.new_ix] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_ix}#{event.new_ix} " - end - - def discard_a(event) - @result << "DA#{event.old_ix}#{event.new_ix} " - end - - def discard_b(event) - @result << "DB#{event.old_ix}#{event.new_ix} " - end - - def change(event) - @result << "C#{event.old_ix}#{event.new_ix} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ 'u', 'abc', 'abc' ], - [ '!', 'def', 'dxf' ], - [ '-', 'yyy', nil ], - [ 'u', 'xxx', 'xxx' ], - [ 'u', 'ghi', 'ghi' ], - [ 'u', 'jkl', 'jkl' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', 'a', nil ], - [ 'u', 'b', 'b' ], - [ 'u', 'c', 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'h', 'f' ], - [ 'u', 'j', 'j' ], - [ '+', nil, 'k' ], - [ 'u', 'l', 'l' ], - [ 'u', 'm', 'm' ], - [ '!', 'n', 'r' ], - [ '!', 'p', 's' ], - [ '+', nil, 't' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ], - [ '-', 'd', nil ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', 'v', 'w' ], - [ '!', 'x', 'y' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', 'x', nil ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'v', 'w' ], - [ '+', nil, 'x' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', nil, 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', 'a', '1' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ 'u', 'c', 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', 'abcd', nil ], - [ '-', 'efgh', nil ], - [ '-', 'ijkl', nil ], - [ '-', 'mnop', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', nil, 'abcd' ], - [ '+', nil, 'efgh' ], - [ '+', nil, 'ijkl' ], - [ '+', nil, 'mnop' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end diff --git a/diff-lcs/tags/release-1.0.4/ChangeLog b/diff-lcs/tags/release-1.0.4/ChangeLog deleted file mode 100644 index 75a392e..0000000 --- a/diff-lcs/tags/release-1.0.4/ChangeLog +++ /dev/null @@ -1,26 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.0.4/Install b/diff-lcs/tags/release-1.0.4/Install deleted file mode 100644 index b583d3f..0000000 --- a/diff-lcs/tags/release-1.0.4/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.0.4.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.0.4/README b/diff-lcs/tags/release-1.0.4/README deleted file mode 100644 index a7021e7..0000000 --- a/diff-lcs/tags/release-1.0.4/README +++ /dev/null @@ -1,66 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.0.4. It contains only bug fixes over 1.0.2 and -1.0.3. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.0.4/diff-lcs.gemspec b/diff-lcs/tags/release-1.0.4/diff-lcs.gemspec deleted file mode 100644 index 93ca917..0000000 --- a/diff-lcs/tags/release-1.0.4/diff-lcs.gemspec +++ /dev/null @@ -1,42 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.0.4} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - s.default_executable = %(ldiff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.0.4/htmldiff b/diff-lcs/tags/release-1.0.4/htmldiff deleted file mode 100644 index ef41888..0000000 --- a/diff-lcs/tags/release-1.0.4/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env 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$ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.0.4" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.0.4/install.rb b/diff-lcs/tags/release-1.0.4/install.rb deleted file mode 100644 index 5772e0b..0000000 --- a/diff-lcs/tags/release-1.0.4/install.rb +++ /dev/null @@ -1,264 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.0.4/ldiff b/diff-lcs/tags/release-1.0.4/ldiff deleted file mode 100644 index a60a19d..0000000 --- a/diff-lcs/tags/release-1.0.4/ldiff +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env ruby -# = Diff::LCS 1.0.4 -# == ldiff Usage -# ldiff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.0.4" -rescue LoadError - require 'diff/lcs' -end - -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -exit Diff::diffprog(ARGV, $stdout, $stderr) diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs.rb deleted file mode 100644 index ad3c1c2..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs.rb +++ /dev/null @@ -1,760 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.0.4 - # Computes "intelligent" differences between two ordered Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the secend sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # === Key Generation - # The Perl version accepts an optional hash-key generation code reference - # because all comparisons are done stringwise. This is not necessary for - # Ruby, as the spaceship operator (<=>) should be provided on classes that - # may be present in an ordered Enumerable. - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written by Mark-Jason Dominus - # <mjd-perl-diff@plover.com>. The basic Ruby implementation was reported - # from the Smalltalk implementation, available at - # ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # +sdiff+ and +traverse_balanced+ were written for the Perl version by - # Mike Schilli <m@perlmeister.com>. - # - # The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed. - module LCS - VERSION = '1.0.4' #:nodoc: - end -end - -require 'diff/lcs/event' -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns the Longest Common Subsequnce(s) - # LCS returns an Array containing the longest common subsequence between - # +self+ and +other+. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - def traverse_sequences(other) - traverse_sequences(self, other, Diff::LCS::YieldingCallbacks) - end - - def traverse_balanced(other) - traverse_balanced(self, other, Diff::LCS::YieldingCallbacks) - end - - def patch(diffs) - Diff::LCS::patch(self, diffs) - end -end - -module Diff::LCS - class << self - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # Compute the longest common subsequence between the ordered Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Given two ordered Enumerables, LCS returns an Array containing their - # longest common subsequence. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - def LCS(a, b, &block) #:yields self[ii] if there are matched subsequences: - matches = Diff::LCS.__lcs(a, b) - ret = [] - matches.each_with_index do |e, ii| - unless matches[ii].nil? - ret << a[ii] - yield a[ii] if block_given? - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. The description is a list of +hunks+; - # each hunk represents a contiguous section of items which should be - # added, deleted, or replaced. The return value of +diff+ is an Array - # of hunks. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # [ [ [ :-, 0, 'a' ] ], - # # [ [ :+, 2, 'd' ] ], - # # [ [ :-, 4, 'h' ], - # # [ :+, 4, 'f' ] ], - # # [ [ :+, 6, 'k' ] ], - # # [ [ :-, 8, 'n' ], - # # [ :-, 9, 'p' ], - # # [ :+, 9, 'r' ], - # # [ :+, 10, 's' ], - # # [ :+, 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at - # position 0 of the first sequence should be deleted (<tt>:-</tt>). - # The second hunk says that the +d+ at position 2 of the second - # sequence should be inserted (<tt>:+</tt>). The third hunk says that - # the +h+ at position 4 of the first sequence should be removed and - # replaced with the +f+ from position 4 of the second sequence. The - # other two hunks similarly. - def diff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::DiffCallbacks.new - traverse_sequences(a, b, callbacks) - callbacks.match(nil) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # same same - # before | after - # old < - - # - > new - # - # It returns an Array of Arrays that contain display instructions. - # Display instructions consist of three elements: A modifier indicator - # (<tt>:+</tt>: Element added, <tt>:-</tt>: Element removed, +u+: - # Element unmodified, +c+: Element changed) and the value of the old - # and new elements, to be displayed side by side. - # - # sdiffs = Diff::LCS.sdiff(seq1, seq2) - # # [ [ '-', 'a', '' ], - # # [ 'u', 'b', 'b' ], - # # [ 'u', 'c', 'c' ], - # # [ '+', '', 'd' ], - # # [ 'u', 'e', 'e' ], - # # [ 'c', 'h', 'f' ], - # # [ 'u', 'j', 'j' ], - # # [ '+', '', 'k' ], - # # [ 'u', 'l', 'l' ], - # # [ 'u', 'm', 'm' ], - # # [ 'c', 'n', 'r' ], - # # [ 'c', 'p', 's' ], - # # [ '+', '', 't' ] ] - def sdiff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::SDiffCallbacks.new - traverse_balanced(a, b, callbacks) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # Imagine that there are two arrows. Arrow A points to an element of - # sequence A, and arrow B points to an element of the sequence B. - # Initially, the arrows point to the first elements of the respective - # sequences. +traverse_sequences+ will advance the arrows through the - # sequences one element at a time, calling an appropriate - # user-specified callback function before each advance. It will - # advance the arrows in such a way that if there are equal elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt> which are equal and which are part - # of the LCS, there will be some moment during the execution of - # +traverse_sequences+ when arrow A is pointing to <tt>A[ii]</tt> and - # arrow B is pointing to <tt>B[jj]</tt>. When this happens, - # +traverse_sequences+ will call the <tt>:match</tt> lambda and then - # it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its - # sequence that is not part of the LCS. +traverse_sequences+ will - # advance that arrow and will call the <tt>:discard_a</tt> or the - # <tt>:discard_b</tt> lambdas, depending on which arrow it advanced. - # If both arrows point to elements that are not part of the LCS, then - # +traverse_sequences+ will advance one of them and call the - # appropriate callback, but it is not specified which it will call. - # - # The arguments to +traverse_sequences+ are the two sequences to - # traverse, and a hash which specifies the lambdas, like this: - # - # traverse_sequences(seq1, seq2, - # :match => callback_1, - # :discard_a => callback_2, - # :discard_b => callback_3) - # - # The lambdas for <tt>:match</tt>, <tt>:discard_a</tt>, and - # <tt>:discard_b</tt> are invoked with the indices of the two arrows - # as their arguments and are not expected to return any values. - # - # If arrow A reaches the end of its sequence before arrow B does, - # +traverse_sequences+ will call the <tt>:a_finished</tt> lambda with - # the last index in A. If <tt>:a_finished</tt> does not exist, then - # <tt>:discard_b</tt> will be called until the end of the B sequence. - # If B terminates before A, then <tt>:b_finished</tt> or - # <tt>:discard_a</tt> will be called. - # - # Omitted callbacks are not called. - # - def traverse_sequences(a, b, callbacks = Diff::LCS::SequenceCallbacks) - matches = Diff::LCS.__lcs(a, b) - - run_finished_a = run_finished_b = false - string = a.kind_of?(String) - - a_size = a.size - b_size = b.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? a[ii, 1] : a[ii] - bx = string ? b[bj, 1] : b[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::Event.new(:discard_a, ax, ii, bx, bj) - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ii, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:match, ax, ii, bx, bj) - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? a[-1, 1] : a[-1] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:finished_a, ax, a_size - 1, bx, bj) - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? a[ai, 1] : a[ai] - loop do - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[-1, 1] : b[-1] - event = Diff::LCS::Event.new(:finished_b, ax, ai, bx, b_size - 1) - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? b[bj, 1] : b[bj] - loop do - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - # +traverse_balanced+ is an alternative to +traverse_sequences+. It - # uses a different algorithm to iterate through the entries in the - # computed LCS. Instead of sticking to one side and showing element - # changes as insertions and deletions only, it will jump back and - # forth between the two sequences and report <em>changes</em> - # occurring as deletions on one side followed immediatly by an - # insertion on the other side. - # - # In addition to the <tt>:discard_a</tt>, <tt>:discard_b</tt>, and - # <tt>:match</tt> callbacks supported by +traverse_sequences+, - # +traverse_balanced+ supports a <tt>:change</tt> callback indicating - # that one element got +replaced+ by another: - # - # traverse_sequences(seq1, seq2, - # :match => $callback_1, - # :discard_a => $callback_2, - # :discard_b => $callback_3, - # :change => $callback_4,) - # - # If no <tt>:change</tt> callback is specified, +traverse_balanced+ - # will map <tt>:change</tt> events to <tt>:discard_a</tt> and - # <tt>:discard_b</tt> actions, therefore resulting in a similar - # behaviour as +traverse_sequences+ with different order of events. - # - # +traverse_balanced+ might be a bit slower than +traverse_sequences+, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # +traverse_balanced+. - def traverse_balanced(a, b, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(a, b) - a_size = a.size - b_size = b.size - ai = bj = mb = 0 - ma = -1 - string = a.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(s) - while (ai < ma) or (bj < mb) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - def __diff_direction(src, diffs) - left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - diffs.each do |change| - text = string ? src[change.position, 1] : src[change.position] - case change.action - when :- - if text == change.text - left += 1 - else - left_miss += 1 - end - when :+ - if text == change.text - right += 1 - else - right_miss += 1 - end - end - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided diff does not appear to apply to the provided value as either source or destination value." - end - end - - # Given a set of diffs, convert the current version to the new version. - def patch(src, diffs, direction = nil) - diffs = diffs.flatten - direction = Diff::LCS.__diff_direction(src, diffs) if direction.nil? - string = src.kind_of?(String) - - n = src.class.new - ai = bj = 0 - - uses_splat = true - - diffs.each do |change| - action = change.action - - if direction == :unpatch - case action - when :- - action = :+ - when :+ - action = :- - end - end - - case action - when :- # Delete - while ai < change.position - n << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += (change.text.kind_of?(String) ? 1 : change.text.size) - when :+ # Insert - while bj < change.position - n << (string ? src[ai, 1]: src[ai]) - ai += 1 - bj += 1 - end - - if change.text.kind_of?(String) - n << change.text - else - n.push(*change.text) - end - - bj += (change.text.kind_of?(String) ? 1 : change.text.size) - end - end - - n - end - - # Given a set of diffs, convert the current version to the prior - # version. - def unpatch(diffs) - patch(diffs, :unpatch) - end - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/array.rb deleted file mode 100644 index fea3edc..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/array.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/block.rb deleted file mode 100644 index 7ffdbab..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/block.rb +++ /dev/null @@ -1,49 +0,0 @@ -#! /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$ -#++ - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/diff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/callbacks.rb deleted file mode 100644 index eb0be60..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,99 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/change' - -class Diff::LCS::SequenceCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::BalancedCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::DiffCallbacks #:nodoc: - attr_accessor :hunk - attr_accessor :diffs - - def initialize - @hunk = [] - @diffs = [] - end - - def match(event) - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_ix, event.old_el) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_ix, event.new_el) - end -end - -class Diff::LCS::SDiffCallbacks #:nodoc: - attr_accessor :diffs - - def initialize - @diffs = [] - end - - def match(event) - @diffs << Diff::LCS::Change.new('u', event.old_el, event.new_el) - end - - def discard_a(event) - @diffs << Diff::LCS::Change.new('-', event.old_el, nil) - end - - def discard_b(event) - @diffs << Diff::LCS::Change.new('+', nil, event.new_el) - end - - def change(event) - @diffs << Diff::LCS::Change.new('!', event.old_el, event.new_el) - end -end - -class Diff::LCS::YieldingCallbacks #:nodoc: - class << self - def method_missing(symbol, *args) - yield args if block_given? - end - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/change.rb deleted file mode 100644 index ae5e904..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/change.rb +++ /dev/null @@ -1,63 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Change - attr_reader :action, :position, :text - - include Comparable - - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.text == other.text) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.text <=> other.text if r.zero? - r - end - - def initialize(action, position, text) - @action = action - @position = position - @text = text - end - - def to_a - [@action, @position, @text] - end - - def self.from_a(*arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - def deleting? - @action == '-' - end - - def adding? - @action == '+' - end - - def unchanged? - @action == 'u' - end - - def changed? - @changed == 'c' - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/event.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/event.rb deleted file mode 100644 index daa2414..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/event.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Event - attr_reader :code - attr_reader :old_el - attr_reader :old_ix - attr_reader :new_el - attr_reader :new_ix - - def initialize(code, a, ai, b, bi) - @code = code - @old_el = a - @old_ix = ai - @new_el = b - @new_ix = bi - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/hunk.rb deleted file mode 100644 index c57e4ba..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,256 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.0.4/lib/diff/lcs/string.rb deleted file mode 100644 index 96a01fe..0000000 --- a/diff-lcs/tags/release-1.0.4/lib/diff/lcs/string.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/array' - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0.4/tests/00test.rb b/diff-lcs/tags/release-1.0.4/tests/00test.rb deleted file mode 100644 index ef8c945..0000000 --- a/diff-lcs/tags/release-1.0.4/tests/00test.rb +++ /dev/null @@ -1,525 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::Change) - diffs.map do |chunks| - chunks.map { |changes| klass.from_a(*changes) } - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_el - @matched_b << event.new_el - end - - def discard_b(event) - @discards_b << event.new_el - end - - def discard_a(event) - @discards_a << event.old_el - end - - def finished_a(event) - @done_a << [event.old_el, event.old_ix] - end - - def finished_b(event) - @done_b << [event.new_el, event.new_ix] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_ix}#{event.new_ix} " - end - - def discard_a(event) - @result << "DA#{event.old_ix}#{event.new_ix} " - end - - def discard_b(event) - @result << "DB#{event.old_ix}#{event.new_ix} " - end - - def change(event) - @result << "C#{event.old_ix}#{event.new_ix} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ 'u', 'abc', 'abc' ], - [ '!', 'def', 'dxf' ], - [ '-', 'yyy', nil ], - [ 'u', 'xxx', 'xxx' ], - [ 'u', 'ghi', 'ghi' ], - [ 'u', 'jkl', 'jkl' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', 'a', nil ], - [ 'u', 'b', 'b' ], - [ 'u', 'c', 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'h', 'f' ], - [ 'u', 'j', 'j' ], - [ '+', nil, 'k' ], - [ 'u', 'l', 'l' ], - [ 'u', 'm', 'm' ], - [ '!', 'n', 'r' ], - [ '!', 'p', 's' ], - [ '+', nil, 't' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ], - [ '-', 'd', nil ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', 'v', 'w' ], - [ '!', 'x', 'y' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', 'x', nil ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', nil, 'x' ], - [ 'u', 'a', 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ], - [ '+', nil, 'd' ], - [ 'u', 'e', 'e' ], - [ '!', 'v', 'w' ], - [ '+', nil, 'x' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', nil, 'a' ], - [ '+', nil, 'b' ], - [ '+', nil, 'c' ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', 'a', '1' ], - [ '-', 'b', nil ], - [ '-', 'c', nil ] ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', 'a', nil ], - [ '-', 'b', nil ], - [ 'u', 'c', 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', 'abcd', nil ], - [ '-', 'efgh', nil ], - [ '-', 'ijkl', nil ], - [ '-', 'mnop', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', nil, 'abcd' ], - [ '+', nil, 'efgh' ], - [ '+', nil, 'ijkl' ], - [ '+', nil, 'mnop' ] - ] - correct_sdiff = __map_diffs([correct_sdiff]) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff[0], sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end diff --git a/diff-lcs/tags/release-1.0/ChangeLog b/diff-lcs/tags/release-1.0/ChangeLog deleted file mode 100644 index 06c33d4..0000000 --- a/diff-lcs/tags/release-1.0/ChangeLog +++ /dev/null @@ -1,5 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.0/Install b/diff-lcs/tags/release-1.0/Install deleted file mode 100644 index f359da0..0000000 --- a/diff-lcs/tags/release-1.0/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.0.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.0/README b/diff-lcs/tags/release-1.0/README deleted file mode 100644 index 7bb69c1..0000000 --- a/diff-lcs/tags/release-1.0/README +++ /dev/null @@ -1,65 +0,0 @@ -Diff::LCS README -================ -This is the 1.0 release of Diff::LCS for Ruby, based originally on Perl's -Algorithm::Diff[1]. It uses the McIlroy-Hunt longest common subsequence (LCS) -algorithm to compute intelligent differences between two sequenced enumerable -containers[2]. The implementation is based on Mario I. Wolczko's[3] Smalltalk -version (1.2, 1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String -will be extended for use this way. - -Copyright -========= -#-- -# 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$ -#++ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the orderr of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.0/diff b/diff-lcs/tags/release-1.0/diff deleted file mode 100644 index 953094d..0000000 --- a/diff-lcs/tags/release-1.0/diff +++ /dev/null @@ -1,230 +0,0 @@ -#!/user/bin/env ruby -# = Diff::LCS 1.0 -# == diff Usage -# diff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' -require 'diff/lcs' -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -diff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - end - end - - output << oldhunk.diff(@format) - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -if __FILE__ == $0 - exit Diff::diffprog(ARGV, $stdout, $stderr) -end diff --git a/diff-lcs/tags/release-1.0/diff-lcs.gemspec b/diff-lcs/tags/release-1.0/diff-lcs.gemspec deleted file mode 100644 index ba17d3d..0000000 --- a/diff-lcs/tags/release-1.0/diff-lcs.gemspec +++ /dev/null @@ -1,44 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.0.0} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) - - s.required_ruby_version = %(0.0.0) - - s.executables = %w(diff htmldiff) - s.bindir = %(bin) - s.default_executable = %(diff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - s.bindir = %{bin} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") -end diff --git a/diff-lcs/tags/release-1.0/diff.bat b/diff-lcs/tags/release-1.0/diff.bat deleted file mode 100644 index 361e045..0000000 --- a/diff-lcs/tags/release-1.0/diff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "diff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "diff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0/htmldiff b/diff-lcs/tags/release-1.0/htmldiff deleted file mode 100644 index 8ad9e95..0000000 --- a/diff-lcs/tags/release-1.0/htmldiff +++ /dev/null @@ -1,104 +0,0 @@ -#! /usr/bin/env 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$ -#++ - -require 'diff/string' -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.0/htmldiff.bat b/diff-lcs/tags/release-1.0/htmldiff.bat deleted file mode 100644 index 1432736..0000000 --- a/diff-lcs/tags/release-1.0/htmldiff.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM -- -REM Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca> -REM adapted from: -REM Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com> -REM Smalltalk by Mario I. Wolczko <mario@wolczko.com> -REM implements McIlroy-Hunt diff algorithm -REM -REM This program is free software. It may be redistributed and/or modified under -REM the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -REM Ruby licence. -REM -REM $Id$ -REM ++ -if "%OS%"=="Windows_NT" goto WinNT -ruby -x "htmldiff" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -ruby -x "htmldiff" %* -goto done -:done diff --git a/diff-lcs/tags/release-1.0/install.rb b/diff-lcs/tags/release-1.0/install.rb deleted file mode 100644 index 0ed8e45..0000000 --- a/diff-lcs/tags/release-1.0/install.rb +++ /dev/null @@ -1,189 +0,0 @@ -## -# Install utility for HaloStatue scripts and libraries. Based heavily on the -# original RDoc installation script by Pragmatic Programmers. -# -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' -require 'test/unit/ui/console/testrunner' - -InstallOptions = OpenStruct.new - - # Set these values to what you want installed. -bins = %w{bin/**/*} -rdoc = %w{bin/**/*.rb lib/**/*.rb README ChangeLog Install} -ri = %w(bin/**/*.rb lib/**/*.rb) -libs = %w{lib/**/*.rb} -tests = %w{tests/**/*.rb} - -def do_bins(bins, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--no-rdoc', FalseClass, - 'Prevents the creation of RDoc output.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--no-ri', FalseClass, - 'Prevents the creation of RI output.') do |onri| - InstallOptions.ri = onri - end - opts.on('--no-tests', FalseClass, - 'Prevents the execution of nit tests.') do |ontest| - InstallOptions.tests = ontest - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers", "--show-hash"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(%w{--ri-site --line-numbers --show-hash} + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -end - -def run_tests(test_list) - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file) - tmp_dir = nil - BinDirs.each do |t| - stat = File.stat(t) rescue next - if stat.directory? and stat.writable? - tmp_dir = t - break - end - end - - fail "Cannot finda temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - opfile += ".rb" if Config::CONFIG["target_os"] =~ /win/ - FileUtils.install(tmp_file, File.join(TargetBinDir, opfile), 0755, true) - FileUtils.unlink(tmp_file) -end - -def glob(list) - g = [] - list.each { |i| g << Dir.glob(i) } - g.flatten! - g.compact! - g -end - -prepare_installation - -bins = glob(bins) -rdoc = glob(rdoc) -ri = glob(ri) -libs = glob(libs) -tests = glob(tests) - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs.rb deleted file mode 100644 index 53ebd33..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs.rb +++ /dev/null @@ -1,758 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.0 - # Computes "intelligent" differences between two ordered Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the secend sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # === Key Generation - # The Perl version accepts an optional hash-key generation code reference - # because all comparisons are done stringwise. This is not necessary for - # Ruby, as the spaceship operator (<=>) should be provided on classes that - # may be present in an ordered Enumerable. - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written by Mark-Jason Dominus - # <mjd-perl-diff@plover.com>. The basic Ruby implementation was reported - # from the Smalltalk implementation, available at - # ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # +sdiff+ and +traverse_balanced+ were written for the Perl version by - # Mike Schilli <m@perlmeister.com>. - # - # The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed. - module LCS - VERSION = '1.0' #:nodoc: - end -end - -require 'diff/lcs/event' -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns the Longest Common Subsequnce(s) - # LCS returns an Array containing the longest common subsequence between - # +self+ and +other+. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - def traverse_sequences(other) - traverse_sequences(self, other, Diff::LCS::YieldingCallbacks) - end - - def traverse_balanced(other) - traverse_balanced(self, other, Diff::LCS::YieldingCallbacks) - end - - def patch(diffs) - Diff::LCS::patch(self, diffs) - end -end - -module Diff::LCS - class << self - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # Compute the longest common subsequence between the ordered Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Given two ordered Enumerables, LCS returns an Array containing their - # longest common subsequence. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - def LCS(a, b, &block) #:yields self[ii] if there are matched subsequences: - matches = Diff::LCS.__lcs(a, b) - ret = [] - matches.each_with_index do |e, ii| - unless matches[ii].nil? - ret << a[ii] - yield a[ii] if block_given? - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. The description is a list of +hunks+; - # each hunk represents a contiguous section of items which should be - # added, deleted, or replaced. The return value of +diff+ is an Array - # of hunks. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # [ [ [ :-, 0, 'a' ] ], - # # [ [ :+, 2, 'd' ] ], - # # [ [ :-, 4, 'h' ], - # # [ :+, 4, 'f' ] ], - # # [ [ :+, 6, 'k' ] ], - # # [ [ :-, 8, 'n' ], - # # [ :-, 9, 'p' ], - # # [ :+, 9, 'r' ], - # # [ :+, 10, 's' ], - # # [ :+, 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at - # position 0 of the first sequence should be deleted (<tt>:-</tt>). - # The second hunk says that the +d+ at position 2 of the second - # sequence should be inserted (<tt>:+</tt>). The third hunk says that - # the +h+ at position 4 of the first sequence should be removed and - # replaced with the +f+ from position 4 of the second sequence. The - # other two hunks similarly. - def diff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::DiffCallbacks.new - traverse_sequences(a, b, callbacks) - callbacks.match(nil) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # same same - # before | after - # old < - - # - > new - # - # It returns an Array of Arrays that contain display instructions. - # Display instructions consist of three elements: A modifier indicator - # (<tt>:+</tt>: Element added, <tt>:-</tt>: Element removed, +u+: - # Element unmodified, +c+: Element changed) and the value of the old - # and new elements, to be displayed side by side. - # - # sdiffs = Diff::LCS.sdiff(seq1, seq2) - # # [ [ '-', 'a', '' ], - # # [ 'u', 'b', 'b' ], - # # [ 'u', 'c', 'c' ], - # # [ '+', '', 'd' ], - # # [ 'u', 'e', 'e' ], - # # [ 'c', 'h', 'f' ], - # # [ 'u', 'j', 'j' ], - # # [ '+', '', 'k' ], - # # [ 'u', 'l', 'l' ], - # # [ 'u', 'm', 'm' ], - # # [ 'c', 'n', 'r' ], - # # [ 'c', 'p', 's' ], - # # [ '+', '', 't' ] ] - def sdiff(a, b, callbacks = nil, &block) - callbacks ||= Diff::LCS::SDiffCallbacks.new - traverse_balanced(a, b, callbacks) - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # Imagine that there are two arrows. Arrow A points to an element of - # sequence A, and arrow B points to an element of the sequence B. - # Initially, the arrows point to the first elements of the respective - # sequences. +traverse_sequences+ will advance the arrows through the - # sequences one element at a time, calling an appropriate - # user-specified callback function before each advance. It will - # advance the arrows in such a way that if there are equal elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt> which are equal and which are part - # of the LCS, there will be some moment during the execution of - # +traverse_sequences+ when arrow A is pointing to <tt>A[ii]</tt> and - # arrow B is pointing to <tt>B[jj]</tt>. When this happens, - # +traverse_sequences+ will call the <tt>:match</tt> lambda and then - # it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its - # sequence that is not part of the LCS. +traverse_sequences+ will - # advance that arrow and will call the <tt>:discard_a</tt> or the - # <tt>:discard_b</tt> lambdas, depending on which arrow it advanced. - # If both arrows point to elements that are not part of the LCS, then - # +traverse_sequences+ will advance one of them and call the - # appropriate callback, but it is not specified which it will call. - # - # The arguments to +traverse_sequences+ are the two sequences to - # traverse, and a hash which specifies the lambdas, like this: - # - # traverse_sequences(seq1, seq2, - # :match => callback_1, - # :discard_a => callback_2, - # :discard_b => callback_3) - # - # The lambdas for <tt>:match</tt>, <tt>:discard_a</tt>, and - # <tt>:discard_b</tt> are invoked with the indices of the two arrows - # as their arguments and are not expected to return any values. - # - # If arrow A reaches the end of its sequence before arrow B does, - # +traverse_sequences+ will call the <tt>:a_finished</tt> lambda with - # the last index in A. If <tt>:a_finished</tt> does not exist, then - # <tt>:discard_b</tt> will be called until the end of the B sequence. - # If B terminates before A, then <tt>:b_finished</tt> or - # <tt>:discard_a</tt> will be called. - # - # Omitted callbacks are not called. - # - def traverse_sequences(a, b, callbacks = Diff::LCS::SequenceCallbacks) - matches = Diff::LCS.__lcs(a, b) - - run_finished_a = run_finished_b = false - string = a.kind_of?(String) - - a_size = a.size - b_size = b.size - ai = bj = 0 - - (0 ... matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? a[ii, 1] : a[ii] - bx = string ? b[bj, 1] : b[bj] - - if b_line.nil? - event = Diff::LCS::Event.new(:discard_a, ax, ii, bx, bj) - callbacks.discard_a(event) - else - loop do - break unless bj < b_line - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ii, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:match, ax, ii, bx, bj) - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? a[-1, 1] : a[-1] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:finished_a, ax, a_size - 1, bx, bj) - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? a[ai, 1] : a[ai] - loop do - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[-1, 1] : b[-1] - event = Diff::LCS::Event.new(:finished_b, ax, ai, bx, b_size - 1) - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? b[bj, 1] : b[bj] - loop do - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - # +traverse_balanced+ is an alternative to +traverse_sequences+. It - # uses a different algorithm to iterate through the entries in the - # computed LCS. Instead of sticking to one side and showing element - # changes as insertions and deletions only, it will jump back and - # forth between the two sequences and report <em>changes</em> - # occurring as deletions on one side followed immediatly by an - # insertion on the other side. - # - # In addition to the <tt>:discard_a</tt>, <tt>:discard_b</tt>, and - # <tt>:match</tt> callbacks supported by +traverse_sequences+, - # +traverse_balanced+ supports a <tt>:change</tt> callback indicating - # that one element got +replaced+ by another: - # - # traverse_sequences(seq1, seq2, - # :match => $callback_1, - # :discard_a => $callback_2, - # :discard_b => $callback_3, - # :change => $callback_4,) - # - # If no <tt>:change</tt> callback is specified, +traverse_balanced+ - # will map <tt>:change</tt> events to <tt>:discard_a</tt> and - # <tt>:discard_b</tt> actions, therefore resulting in a similar - # behaviour as +traverse_sequences+ with different order of events. - # - # +traverse_balanced+ might be a bit slower than +traverse_sequences+, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # +traverse_balanced+. - def traverse_balanced(a, b, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(a, b) - a_size = a.size - b_size = b.size - ai = bj = mb = 0 - ma = -1 - string = a.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(s) - while (ai < ma) or (bj < mb) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, ax, ai, bx, bj) - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - event = Diff::LCS::Event.new(:discard_a, ax, ai, bx, bj) - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? a[ai, 1] : a[ai] - bx = string ? b[bj, 1] : b[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::Event.new(:change, ax, ai, bx, bj) - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - ax = string ? a[ai, 1] : a[ai] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::Event.new(:discard_a, a[ai], ai, b[bj], bj) - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::Event.new(:discard_b, a[ai], ai, b[bj], bj) - callbacks.discard_b(event) - bj += 1 - end - end - end - - def __diff_direction(src, diffs) - left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - diffs.each do |change| - text = string ? src[change.position, 1] : src[change.position] - case change.action - when :- - if text == change.text - left += 1 - else - left_miss += 1 - end - when :+ - if text == change.text - right += 1 - else - right_miss += 1 - end - end - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided diff does not appear to apply to the provided value as either source or destination value." - end - end - - # Given a set of diffs, convert the current version to the new version. - def patch(src, diffs, direction = nil) - diffs = diffs.flatten - direction = Diff::LCS.__diff_direction(src, diffs) if direction.nil? - string = src.kind_of?(String) - - n = src.class.new - ai = bj = 0 - - uses_splat = true - - diffs.each do |change| - action = change.action - - if direction == :unpatch - case action - when :- - action = :+ - when :+ - action = :- - end - end - - case action - when :- # Delete - while ai < change.position - n << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += (change.text.kind_of?(String) ? 1 : change.text.size) - when :+ # Insert - while bj < change.position - n << (string ? src[ai, 1]: src[ai]) - ai += 1 - bj += 1 - end - - if change.text.kind_of?(String) - n << change.text - else - n.push(*change.text) - end - - bj += (change.text.kind_of?(String) ? 1 : change.text.size) - end - end - - n - end - - # Given a set of diffs, convert the current version to the prior - # version. - def unpatch(diffs) - patch(diffs, :unpatch) - end - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/array.rb deleted file mode 100644 index fea3edc..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/array.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/block.rb deleted file mode 100644 index 7ffdbab..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/block.rb +++ /dev/null @@ -1,49 +0,0 @@ -#! /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$ -#++ - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/diff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/callbacks.rb deleted file mode 100644 index eb0be60..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,99 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/change' - -class Diff::LCS::SequenceCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::BalancedCallbacks #:nodoc: - class << self - def match(event) - event - end - def discard_a(event) - event - end - def discard_b(event) - event - end - end -end - -class Diff::LCS::DiffCallbacks #:nodoc: - attr_accessor :hunk - attr_accessor :diffs - - def initialize - @hunk = [] - @diffs = [] - end - - def match(event) - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_ix, event.old_el) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_ix, event.new_el) - end -end - -class Diff::LCS::SDiffCallbacks #:nodoc: - attr_accessor :diffs - - def initialize - @diffs = [] - end - - def match(event) - @diffs << Diff::LCS::Change.new('u', event.old_el, event.new_el) - end - - def discard_a(event) - @diffs << Diff::LCS::Change.new('-', event.old_el, nil) - end - - def discard_b(event) - @diffs << Diff::LCS::Change.new('+', nil, event.new_el) - end - - def change(event) - @diffs << Diff::LCS::Change.new('!', event.old_el, event.new_el) - end -end - -class Diff::LCS::YieldingCallbacks #:nodoc: - class << self - def method_missing(symbol, *args) - yield args if block_given? - end - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/change.rb deleted file mode 100644 index a472f26..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/change.rb +++ /dev/null @@ -1,63 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Change - attr_reader :action, :position, :text - - include Comparable - - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.text == other.text) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.text <=> other.text if r.zero? - r - end - - def initialize(action, position, text) - @action = action - @position = position - @text = text - end - - def to_a - [@action, @position, @text] - end - - def self.from_a(*arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - def deleting? - @action == :- - end - - def adding? - @action == :+ - end - - def unchanged? - @action == :u - end - - def changed? - @changed == :c - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/event.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/event.rb deleted file mode 100644 index daa2414..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/event.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /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$ -#++ - -class Diff::LCS::Event - attr_reader :code - attr_reader :old_el - attr_reader :old_ix - attr_reader :new_el - attr_reader :new_ix - - def initialize(code, a, ai, b, bi) - @code = code - @old_el = a - @old_ix = ai - @new_el = b - @new_ix = bi - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/hunk.rb deleted file mode 100644 index c57e4ba..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,256 +0,0 @@ -#! /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$ -#++ - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.0/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.0/lib/diff/lcs/string.rb deleted file mode 100644 index 96a01fe..0000000 --- a/diff-lcs/tags/release-1.0/lib/diff/lcs/string.rb +++ /dev/null @@ -1,20 +0,0 @@ -#! /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$ -#++ - -require 'diff/array' - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.0/tests/00test.rb b/diff-lcs/tags/release-1.0/tests/00test.rb deleted file mode 100644 index e2613d5..0000000 --- a/diff-lcs/tags/release-1.0/tests/00test.rb +++ /dev/null @@ -1,431 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -if __FILE__ == $0 - class TestLCS < Test::Unit::TestCase - def setup - @a = %w(a b c e h j l m n p) - @b = %w(b c d e f j k l m r s t) - - @correct = %w(b c e j l m) - @skipped_a = "a h n p" - @skipped_b = "d f k r s t" - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '+', 9, 'r' ], - [ '-', 9, 'p' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff) - end - - def __map_diffs(diffs) - diffs.map do |chunks| - chunks.map do |changes| - Diff::LCS::Change.from_a(*changes) - end - end - end - - def __make_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_el - @matched_b << event.new_el - end - - def discard_b(event) - @discards_b << event.new_el - end - - def discard_a(event) - @discards_a << event.old_el - end - - def finished_a(event) - @done_a << [event.old_el, event.old_ix] - end - - def finished_b(event) - @done_b << [event.new_el, event.new_ix] - end - end - callbacks.reset - callbacks - end - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@a, @b) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct.size) - assert_nothing_raised { ares = (0...res.size).map { |i| res[i] ? @a[i] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |i| res[i] ? @b[res[i]] : nil } } - assert_equal(@correct, ares.compact) - assert_equal(@correct, bres.compact) - end - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __make_callbacks - class << callbacks - undef finished_a - undef finished_b - end - end - assert_nothing_raised { Diff::LCS.traverse_sequences(@a, @b, callbacks) } - assert_equal(@correct.size, callbacks.matched_a.size) - assert_equal(@correct.size, callbacks.matched_b.size) - assert_equal(@skipped_a, callbacks.discards_a.join(" ")) - assert_equal(@skipped_b, callbacks.discards_b.join(" ")) - assert_nothing_raised { callbacks = __make_callbacks } - assert_nothing_raised { Diff::LCS.traverse_sequences(@a, @b, callbacks) } - assert_equal(@correct.size, callbacks.matched_a.size) - assert_equal(@correct.size, callbacks.matched_b.size) - assert_equal(@skipped_a, callbacks.discards_a.join(" ")) - assert_equal(@skipped_b, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - end - - def test_LCS - res = nil - assert_nothing_raised { res = Diff::LCS.LCS(@a, @b) } - assert_equal(res.compact, @correct) - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@a, @b) } - assert_equal(@correct_diff, diff) - end - - def test_sdiff_a - sdiff = nil - a = %w(abc def yyy xxx ghi jkl) - b = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - ['u', 'abc', 'abc'], - ['!', 'def', 'dxf'], - ['-', 'yyy', nil], - ['u', 'xxx', 'xxx'], - ['u', 'ghi', 'ghi'], - ['u', 'jkl', 'jkl'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - ['-', 'a', nil], - ['u', 'b', 'b'], - ['u', 'c', 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'], - ['!', 'h', 'f'], - ['u', 'j', 'j'], - ['+', nil, 'k'], - ['u', 'l', 'l'], - ['u', 'm', 'm'], - ['!', 'n', 'r'], - ['!', 'p', 's'], - ['+', nil, 't'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@a, @b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - a = %w(a b c d e) - b = %w(a e) - correct_sdiff = [ - ['u', 'a', 'a' ], - ['-', 'b', nil ], - ['-', 'c', nil ], - ['-', 'd', nil ], - ['u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - a = %w(a e) - b = %w(a b c d e) - correct_sdiff = [ - ['u', 'a', 'a' ], - ['+', nil, 'b' ], - ['+', nil, 'c' ], - ['+', nil, 'd' ], - ['u', 'e', 'e' ] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - a = %w(v x a e) - b = %w(w y a b c d e) - correct_sdiff = [ - ['!', 'v', 'w' ], - ['!', 'x', 'y' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - a = %w(x a e) - b = %w(a b c d e) - correct_sdiff = [ - ['-', 'x', nil ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - a = %w(a e) - b = %w(x a b c d e) - correct_sdiff = [ - ['+', nil, 'x' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'] ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - a = %w(a e v) - b = %w(x a b c d e w x) - correct_sdiff = [ - ['+', nil, 'x' ], - ['u', 'a', 'a' ], - ['+', nil, 'b'], - ['+', nil, 'c'], - ['+', nil, 'd'], - ['u', 'e', 'e'], - ['!', 'v', 'w'], - ['+', nil, 'x'] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - a = %w() - b = %w(a b c) - correct_sdiff = [ - ['+', nil, 'a' ], - ['+', nil, 'b' ], - ['+', nil, 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - a = %w(a b c) - b = %w() - correct_sdiff = [ - ['-', 'a', nil ], - ['-', 'b', nil ], - ['-', 'c', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - a = %w(a b c) - b = %w(1) - correct_sdiff = [ - ['!', 'a', '1' ], - ['-', 'b', nil ], - ['-', 'c', nil ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - a = %w(a b c) - b = %w(c) - correct_sdiff = [ - ['-', 'a', nil ], - ['-', 'b', nil ], - ['u', 'c', 'c' ] - ] - correct_sdiff = __map_diffs([correct_sdiff])[0] - assert_nothing_raised { sdiff = Diff::LCS.sdiff(a, b) } - assert_equal(correct_sdiff, sdiff) - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M #{event.old_ix} #{event.new_ix}" - end - - def discard_a(event) - @result << "DA #{event.old_ix} #{event.new_ix}" - end - - def discard_b(event) - @result << "DB #{event.old_ix} #{event.new_ix}" - end - - def change(event) - @result << "C #{event.old_ix} #{event.new_ix}" - end - end - cb.reset - cb - end - - def test_balanced_a - a = %w(a b c) - b = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0C 1 1M 2 2", callback.result) - end - - def test_balanced_b - a = %w(a b c) - b = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0DA 1 1DB 2 1M 2 2", callback.result) - end - - def test_balanced_c - a = %w(a x y c) - b = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0C 1 1C 2 2M 3 3", callback.result) - end - - def test_balanced_d - a = %w(x y c) - b = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1M 2 2", callback.result) - end - - def test_balanced_e - a = %w(a x y z) - b = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1C 2 2DA 3 3", callback.result) - end - - def test_balanced_f - a = %w(a z) - b = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("M 0 0DA 1 1", callback.result) - end - - def test_balanced_g - a = %w(z a) - b = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("DA 0 0M 1 0", callback.result) - end - - def test_balanced_h - a = %w(a b c) - b = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(a, b, callback) } - assert_equal("C 0 0C 1 1C 2 2", callback.result) - end - end -end diff --git a/diff-lcs/tags/release-1.1.0/ChangeLog b/diff-lcs/tags/release-1.1.0/ChangeLog deleted file mode 100644 index a9f012f..0000000 --- a/diff-lcs/tags/release-1.1.0/ChangeLog +++ /dev/null @@ -1,33 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.1.0 -* Eliminated the need for Diff::LCS::Event and removed it. -* Added a contextual diff callback, Diff::LCS::ContextDiffCallback. -* Implemented patching/unpatching for standard Diff callback output formats - with both #diff and #sdiff. -* Extensive documentation changes. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.1.0/Install b/diff-lcs/tags/release-1.1.0/Install deleted file mode 100644 index 825629b..0000000 --- a/diff-lcs/tags/release-1.1.0/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.1.0.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.1.0/README b/diff-lcs/tags/release-1.1.0/README deleted file mode 100644 index cf5156c..0000000 --- a/diff-lcs/tags/release-1.1.0/README +++ /dev/null @@ -1,76 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.1.0 with the addition of new features, -including the ability to #patch and #unpatch changes as well as a new -contextual diff callback, Diff::LCS::ContextDiffCallbacks, that should -improve the context sensitivity of patching. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - seq2 == Diff::LCS.patch!(seq1, diffs) - seq1 == Diff::LCS.unpatch!(seq2, diffs) - seq2 == Diff::LCS.patch!(seq1, sdiff) - seq1 == Diff::LCS.unpatch!(seq2, sdiff) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - seq2 == seq1.patch!(diffs) - seq1 == seq2.unpatch!(diffs) - seq2 == seq1.patch!(sdiff) - seq1 == seq2.unpatch!(sdiff) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.1.0/diff-lcs.gemspec b/diff-lcs/tags/release-1.1.0/diff-lcs.gemspec deleted file mode 100644 index 2e8d2b7..0000000 --- a/diff-lcs/tags/release-1.1.0/diff-lcs.gemspec +++ /dev/null @@ -1,42 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.1.0} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - s.platform = Gem::Platform::RUBY - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - s.default_executable = %(ldiff) - - s.test_suite_file = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.1.0/htmldiff b/diff-lcs/tags/release-1.1.0/htmldiff deleted file mode 100644 index 6140410..0000000 --- a/diff-lcs/tags/release-1.1.0/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env 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$ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.1.0" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.1.0/install.rb b/diff-lcs/tags/release-1.1.0/install.rb deleted file mode 100644 index 5772e0b..0000000 --- a/diff-lcs/tags/release-1.1.0/install.rb +++ /dev/null @@ -1,264 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.1.0/ldiff b/diff-lcs/tags/release-1.1.0/ldiff deleted file mode 100644 index 4525991..0000000 --- a/diff-lcs/tags/release-1.1.0/ldiff +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env ruby -# = Diff::LCS 1.1.0 -# == ldiff Usage -# ldiff [options] oldfile newfile -# -# -c:: Displays a context diff with 3 lines of context. -# -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. -# -u:: Displays a unified diff with 3 lines of context. -# -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. -# -e:: Creates an 'ed' script to change oldfile to newfile. -# -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. -# -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. -# --binary:: Treats the files as binary. -# -q, --brief:: Reports only whether or not the files differ, not the details. -# --help:: Shows the command-line help. -# --version:: Shows the version of Diff::LCS. -# -# By default, runs produces an "old-style" diff, with output like UNIX diff. -# -# == Copyright -# Copyright © 2004 Austin Ziegler -# -# Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> -# Austin Ziegler <diff-lcs@halostatue.ca> -# -# 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. - -require 'optparse' -require 'ostruct' - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.1.0" -rescue LoadError - require 'diff/lcs' -end - -require 'diff/lcs/hunk' - -module Diff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def diffprog(args, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end - -exit Diff::diffprog(ARGV, $stdout, $stderr) diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs.rb b/diff-lcs/tags/release-1.1.0/lib/diff/lcs.rb deleted file mode 100644 index 7740231..0000000 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs.rb +++ /dev/null @@ -1,1070 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.1.0 - # Computes "intelligent" differences between two sequenced Enumerables. This - # is an implementation of the McIlroy-Hunt "diff" algorithm for Enumerable - # objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version (1.2, - # 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = seq1.traverse_sequences(seq2, callback_obj) - # bal = seq1.traverse_balanced(seq2, callback_obj) - # - # Default extensions are provided for Array and String objects through the - # use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # - # <em>The following text is from the Perl documentation. The only changes - # have been to make the text appear better in Rdoc</em>. - # - # I once read an article written by the authors of +diff+; they said that - # they hard worked very hard on the algorithm until they found the right - # one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the second sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. Documentation includes work by Mark-Jason Dominus. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written originally by Mark-Jason - # Dominus <mjd-perl-diff@plover.com> and later by Ned Konz. The basic Ruby - # implementation was re-ported from the Smalltalk implementation, available - # at ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # #sdiff and #traverse_balanced were written for the Perl version by Mike - # Schilli <m@perlmeister.com>. - # - # "The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed." - module LCS - VERSION = '1.1.0' - end -end - -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns an Array containing the longest common subsequence(s) between - # +self+ and +other+. See Diff::LCS#LCS. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - # Returns the difference set between +self+ and +other+. See - # Diff::LCS#diff. - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - # Returns the balanced ("side-by-side") difference set between +self+ and - # +other+. See Diff::LCS#sdiff. - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+. See Diff::LCS#traverse_sequences. - def traverse_sequences(other, callbacks = nil, &block) - traverse_sequences(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+ using the alternate, balanced algorithm. See - # Diff::LCS#traverse_balanced. - def traverse_balanced(other, callbacks = nil, &block) - traverse_balanced(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Attempts to patch +self+ with the provided +patchset+. See Diff::LCS#patch. - def patch(patchset) - Diff::LCS::patch(self, patchset) - end - - # Attempts to unpatch +self+ with the provided +patchset+. See - # Diff::LCS#patch!. Does no autodiscovery. - def patch!(patchset) - Diff::LCS::patch!(self, patchset) - end - - # Attempts to unpatch +self+ with the provided +patchset+. See - # Diff::LCS#unpatch. Does no autodiscovery. - def unpatch!(patchset) - Diff::LCS::unpatch!(self, patchset) - end -end - -module Diff::LCS - class << self - # Given two sequenced Enumerables, LCS returns an Array containing their - # longest common subsequences. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # - # This array whose contents is such that: - # - # lcs.each_with_index do |ee, ii| - # assert(ee.nil? || (seq1[ii] == seq2[ee])) - # end - # - # If a block is provided, the matching subsequences will be yielded from - # +seq1+ in turn and may be modified before they are placed into the - # returned Array of subsequences. - def LCS(seq1, seq2, &block) #:yields seq1[ii] for each matched: - matches = Diff::LCS.__lcs(seq1, seq2) - ret = [] - matches.each_with_index do |ee, ii| - unless matches[ii].nil? - if block_given? - ret << (yield seq1[ii]) - else - ret << seq1[ii] - end - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. - # - # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If - # a Class argument is provided for +callbacks+, #diff will attempt to - # initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes: - callbacks ||= Diff::LCS::DiffCallbacks - callbacks = callbacks.new if callbacks.kind_of?(Class) - traverse_sequences(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # old < - - # same same - # before | after - # - > new - # - # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If - # a Class argument is provided for +callbacks+, #diff will attempt to - # initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes: - callbacks ||= Diff::LCS::SDiffCallbacks - callbacks = callbacks.new if callbacks.kind_of?(Class) - traverse_balanced(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # The arguments to #traverse_sequences are the two sequences to - # traverse, and a callback object, like this: - # - # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #diff is implemented with #traverse_sequences. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#finished_a</em>:: Called when +a+ has reached the end of - # sequence +A+. - # <em>callbacks#finished_b</em>:: Called when +b+ has reached the end of - # sequence +B+. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, depending - # on which arrow it advanced. If both arrows point to elements that are - # not part of the longest common subsequence, then #traverse_sequences - # will advance one of them and call the appropriate callback, but it is - # not specified which it will call. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # and <tt>callbacks#discard_b</tt> are invoked with an event comprising - # the action ("=", "+", or "-", respectively), the indicies +ii+ and - # +jj+, and the elements <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return - # values are discarded by #traverse_sequences. - # - # === End of Sequences - # If arrow +a+ reaches the end of its sequence before arrow +b+ does, - # #traverse_sequence try to call <tt>callbacks#finished_a</tt> with the - # last index and element of +A+ (<tt>A[-1]</tt>) and the current index - # and element of +B+ (<tt>B[jj]</tt>). If <tt>callbacks#finished_a</tt> - # does not exist, then <tt>callbacks#discard_b</tt> will be called on - # each element of +B+ until the end of the sequence is reached (the call - # will be done with <tt>A[-1]</tt> and <tt>B[jj]</tt> for each element). - # - # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+, - # <tt>callbacks#finished_b</tt> will be called with the current index - # and element of +A+ (<tt>A[ii]</tt>) and the last index and element of - # +B+ (<tt>A[-1]</tt>). Again, if <tt>callbacks#finished_b</tt> does not - # exist on the callback object, then <tt>callbacks#discard_a</tt> will - # be called on each element of +A+ until the end of the sequence is - # reached (<tt>A[ii]</tt> and <tt>B[-1]</tt>). - # - # There is a chance that one additional <tt>callbacks#discard_a</tt> or - # <tt>callbacks#discard_b</tt> will be called after the end of the - # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+ - # has not yet reached the end of +B+. - def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events: - matches = Diff::LCS.__lcs(seq1, seq2) - - run_finished_a = run_finished_b = false - string = seq1.kind_of?(String) - - a_size = seq1.size - b_size = seq2.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? seq1[ii, 1] : seq1[ii] - bx = string ? seq2[bj, 1] : seq2[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::ContextChange.new('-', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? seq1[-1, 1] : seq1[-1] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx) - event = yield event if block_given? - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? seq1[ai, 1] : seq1[ai] - loop do - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[-1, 1] : seq2[-1] - event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx) - event = yield event if block_given? - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? seq2[bj, 1] : seq2[bj] - loop do - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - # #traverse_balanced is an alternative to #traverse_sequences. It - # uses a different algorithm to iterate through the entries in the - # computed longest common subsequence. Instead of viewing the changes as - # insertions or deletions from one of the sequences, #traverse_balanced - # will report <em>changes</em> between the sequences. To represent a - # - # The arguments to #traverse_balanced are the two sequences to traverse - # and a callback object, like this: - # - # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #sdiff is implemented with #traverse_balanced. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#change</em>:: Called when +a+ and +b+ are pointing - # to the same relative position, but - # <tt>A[a]</tt> and <tt>B[b]</tt> are - # not the same; a <em>change</em> has - # occurred. - # - # #traverse_balanced might be a bit slower than #traverse_sequences, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # #traverse_balanced. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # === Matches - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # === Discards - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, - # depending on which arrow it advanced. - # - # === Changes - # If both +a+ and +b+ point to elements that are not part of the longest - # common subsequence, then #traverse_sequences will try to call - # <tt>callbacks#change</tt> and advance both arrows. If - # <tt>callbacks#change</tt> is not implemented, then - # <tt>callbacks#discard_a</tt> and <tt>callbacks#discard_b</tt> will be - # called in turn. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # <tt>callbacks#discard_b</tt>, and <tt>callbacks#change</tt> are - # invoked with an event comprising the action ("=", "+", "-", or "!", - # respectively), the indicies +ii+ and +jj+, and the elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return values are discarded by - # #traverse_balanced. - # - # === Context - # Note that +ii+ and +jj+ may not be the same index position, even if - # +a+ and +b+ are considered to be pointing to matching or changed - # elements. - def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(seq1, seq2) - a_size = seq1.size - b_size = seq2.size - ai = bj = mb = 0 - ma = -1 - string = seq1.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(seq2) - while (ai < ma) or (bj < mb) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - PATCH_MAP = { #:nodoc: - :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }, - :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' } - } - - # Given a patchset, convert the current version to the new - # version. If +direction+ is not specified (must be - # <tt>:patch</tt> or <tt>:unpatch</tt>), then discovery of the - # direction of the patch will be attempted. - def patch(src, patchset, direction = nil) - string = src.kind_of?(String) - # Start with a new empty type of the source's class - res = src.class.new - - # Normalize the patchset. - patchset = __normalize_patchset(patchset) - - direction ||= Diff::LCS.__diff_direction(src, patchset) - direction ||= :patch - - ai = bj = 0 - - patchset.each do |change| - # Both Change and ContextChange support #action - action = PATCH_MAP[direction][change.action] - - case change - when Diff::LCS::ContextChange - case direction - when :patch - el = change.new_element - op = change.old_position - np = change.new_position - when :unpatch - el = change.old_element - op = change.new_position - np = change.old_position - end - - case action - when '-' # Remove details from the old string - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < np - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res << el - bj += 1 - when '=' - # This only appears in sdiff output with the SDiff callback. - # Therefore, we only need to worry about dealing with a single - # element. - res << el - - ai += 1 - bj += 1 - when '!' - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - ai += 1 - - res << el - end - when Diff::LCS::Change - case action - when '-' - while ai < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - - res << change.element - end - end - end - - res - end - - # Given a set of patchset, convert the current version to the prior - # version. Does no auto-discovery. - def unpatch!(src, patchset) - Diff::LCS.patch(src, patchset, :unpatch) - end - - # Given a set of patchset, convert the current version to the next - # version. Does no auto-discovery. - def patch!(src, patchset) - Diff::LCS.patch(src, patchset, :patch) - end - -# private - # Compute the longest common subsequence between the sequenced Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. (Currently unused.) - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Examine the patchset and the source to see in which direction the - # patch should be applied. - # - # WARNING: By default, this examines the whole patch, so this could take - # some time. This also works better with Diff::LCS::ContextChange or - # Diff::LCS::Change as its source, as an array will cause the creation - # of one of the above. - def __diff_direction(src, patchset, limit = nil) - count = left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - patchset.each do |change| - count += 1 - - case change - when Diff::LCS::Change - # With a simplistic change, we can't tell the difference between - # the left and right on '!' actions, so we ignore those. On '=' - # actions, if there's a miss, we miss both left and right. - element = string ? src[change.position, 1] : src[change.position] - - case change.action - when '-' - if element == change.element - left += 1 - else - left_miss += 1 - end - when '+' - if element == change.element - right += 1 - else - right_miss += 1 - end - when '=' - if element != change.element - left_miss += 1 - right_miss += 1 - end - end - when Diff::LCS::ContextChange - case change.action - when '-' # Remove details from the old string - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - left_miss += 1 - end - when '+' - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - right_miss += 1 - end - when '=' - le = string ? src[change.old_position, 1] : src[change.old_position] - re = string ? src[change.new_position, 1] : src[change.new_position] - - left_miss += 1 if le != change.old_element - right_miss += 1 if re != change.new_element - when '!' - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - left_miss += 1 - right_miss += 1 - end - end - end - end - - break if not limit.nil? and count > limit - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided patchset does not appear to apply to the provided value as either source or destination value." - end - end - - # Normalize the patchset. A patchset is always a sequence of changes, but - # how those changes are represented may vary, depending on how they were - # generated. In all cases we support, we also support the array - # representation of the changes. The formats are: - # - # [ # patchset <- Diff::LCS.diff(a, b) - # [ # one or more hunks - # Diff::LCS::Change # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, line, value ] # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.diff(a, b, Diff::LCS::ContextDiffCallbacks) - # # OR <- Diff::LCS.sdiff(a, b, Diff::LCS::ContextDiffCallbacks) - # [ # one or more hunks - # Diff::LCS::ContextChange # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.sdiff(a, b) - # # OR <- Diff::LCS.diff(a, b, Diff::LCS::SDiffCallbacks) - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset, equivalent to the above - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] - # - # The result of this will be either of the following. - # - # [ # patchset - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset - # Diff::LCS::Change # one or more changes - # ] - # - # If either of the above is provided, it will be returned as such. - # - def __normalize_patchset(patchset) - patchset.map do |hunk| - case hunk - when Diff::LCS::ContextChange, Diff::LCS::Change - hunk - when Array - if (not hunk[0].kind_of?(Array)) and hunk[1].kind_of?(Array) and hunk[2].kind_of?(Array) - Diff::LCS::ContextChange.from_a(hunk) - else - hunk.map do |change| - case change - when Diff::LCS::ContextChange, Diff::LCS::Change - change - when Array - # change[1] will ONLY be an array in a ContextChange#to_a call. - # In Change#to_a, it represents the line (singular). - if change[1].kind_of?(Array) - Diff::LCS::ContextChange.from_a(change) - else - Diff::LCS::Change.from_a(change) - end - end - end - end - else - raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}." - end - end.flatten - end - end -end diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.1.0/lib/diff/lcs/callbacks.rb deleted file mode 100644 index a786daf..0000000 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,320 +0,0 @@ -#! /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$ -#++ -# Contains definitions for all default callback objects. - -require 'diff/lcs/change' - -module Diff::LCS - # This callback object implements the default set of callback events, which - # only returns the event itself. Note that #finished_a and #finished_b are - # not implemented -- I haven't yet figured out where they would be useful. - # - # Note that this is intended to be called as is, e.g., - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks) - class DefaultCallbacks - class << self - # Called when two items match. - def match(event) - event - end - # Called when the old value is discarded in favour of the new value. - def discard_a(event) - event - end - # Called when the new value is discarded in favour of the old value. - def discard_b(event) - event - end - # Called when both the old and new values have changed. - def change(event) - event - end - end - end - - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_sequences. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks) - SequenceCallbacks = DefaultCallbacks - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_balanced. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks) - BalancedCallbacks = DefaultCallbacks -end - - # This will produce a compound array of simple diff change objects. Each - # element in the #diffs array is a +hunk+ or +hunk+ array, where each - # element in each +hunk+ array is a single Change object representing the - # addition or removal of a single element from one of the two tested - # sequences. The +hunk+ provides the full context for the changes. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ [ '-', 0, 'a' ] ], # 1 - # # [ [ '+', 2, 'd' ] ], # 2 - # # [ [ '-', 4, 'h' ], # 3 - # # [ '+', 4, 'f' ] ], - # # [ [ '+', 6, 'k' ] ], # 4 - # # [ [ '-', 8, 'n' ], # 5 - # # [ '-', 9, 'p' ], - # # [ '+', 9, 'r' ], - # # [ '+', 10, 's' ], - # # [ '+', 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at position 0 - # of the first sequence should be deleted (<tt>'-'</tt>). The second hunk - # says that the +d+ at position 2 of the second sequence should be inserted - # (<tt>'+'</tt>). The third hunk says that the +h+ at position 4 of the - # first sequence should be removed and replaced with the +f+ from position 4 - # of the second sequence. The other two hunks are described similarly. - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#diff - # method. - # - # cbo = Diff::LCS::DiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::DiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize # :yields self: - @hunk = [] - @diffs = [] - - if block_given? - begin - yield self - ensure - self.finish - end - end - end - - # Finalizes the diff process. If an unprocessed hunk still exists, then it - # is appended to the diff list. - def finish - add_nonempty_hunk - end - - def match(event) - add_nonempty_hunk - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_position, event.old_element) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_position, event.new_element) - end - -private - def add_nonempty_hunk - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end -end - - # This will produce a compound array of contextual diff change objects. Each - # element in the #diffs array is a "hunk" array, where each element in each - # "hunk" array is a single change. Each change is a Diff::LCS::ContextChange - # that contains both the old index and new index values for the change. The - # "hunk" provides the full context for the changes. Both old and new objects - # will be presented for changed objects. +nil+ will be substituted for a - # discarded object. - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks) - # # This example shows a simplified array format. - # # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1 - # # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2 - # # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3 - # # [ '+', [ 5, nil ], [ 4, 'f' ] ] ], - # # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4 - # # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5 - # # [ '+', [ 9, nil ], [ 9, 'r' ] ], - # # [ '-', [ 9, 'p' ], [ 10, nil ] ], - # # [ '+', [ 10, nil ], [ 10, 's' ] ], - # # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ] - # - # The five hunks shown are comprised of individual changes; if there is a - # related set of changes, they are still shown individually. - # - # This callback can also be used with Diff::LCS#sdiff, which will produce - # results like: - # - # diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks) - # # This example shows a simplified array format. - # # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1 - # # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2 - # # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3 - # # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4 - # # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5 - # # [ "!", [ 9, "p" ], [ 10, "s" ] ], - # # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ] - # - # The five hunks are still present, but are significantly shorter in total - # presentation, because changed items are shown as changes ("!") instead of - # potentially "mismatched" pairs of additions and deletions. - # - # The result of this operation is similar to that of - # Diff::LCS::SDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and can be used by the - # Diff::LCS#diff or Diff::LCS#sdiff methods. - # - # cbo = Diff::LCS::ContextDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::ContextDiffCallbacks < Diff::LCS::DiffCallbacks - def discard_a(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end -end - - # This will produce a simple array of diff change objects. Each element in - # the #diffs array is a single ContextChange. In the set of #diffs provided - # by SDiffCallbacks, both old and new objects will be presented for both - # changed <strong>and unchanged</strong> objects. +nil+ will be substituted - # for a discarded object. - # - # The diffset produced by this callback, when provided to Diff::LCS#sdiff, - # will compute and display the necessary components to show two sequences - # and their minimized differences side by side, just like the Unix utility - # +sdiff+. - # - # same same - # before | after - # old < - - # - > new - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.sdiff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ "-", [ 0, "a"], [ 0, nil ] ], - # # [ "=", [ 1, "b"], [ 0, "b" ] ], - # # [ "=", [ 2, "c"], [ 1, "c" ] ], - # # [ "+", [ 3, nil], [ 2, "d" ] ], - # # [ "=", [ 3, "e"], [ 3, "e" ] ], - # # [ "!", [ 4, "h"], [ 4, "f" ] ], - # # [ "=", [ 5, "j"], [ 5, "j" ] ], - # # [ "+", [ 6, nil], [ 6, "k" ] ], - # # [ "=", [ 6, "l"], [ 7, "l" ] ], - # # [ "=", [ 7, "m"], [ 8, "m" ] ], - # # [ "!", [ 8, "n"], [ 9, "r" ] ], - # # [ "!", [ 9, "p"], [ 10, "s" ] ], - # # [ "+", [ 10, nil], [ 11, "t" ] ] ] - # - # The result of this operation is similar to that of - # Diff::LCS::ContextDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#sdiff - # method. - # - # cbo = Diff::LCS::SDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # - # As with the other initialisable callback objects, Diff::LCS::SDiffCallbacks - # can be initialised with a block. As there is no "fininishing" to be done, - # this has no effect on the state of the object. - # - # cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.to_a } -class Diff::LCS::SDiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize #:yields self: - @diffs = [] - yield self if block_given? - end - - def match(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_a(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end -end diff --git a/diff-lcs/tags/release-1.1.0/tests/00test.rb b/diff-lcs/tags/release-1.1.0/tests/00test.rb deleted file mode 100644 index e603d39..0000000 --- a/diff-lcs/tags/release-1.1.0/tests/00test.rb +++ /dev/null @@ -1,595 +0,0 @@ -#! /usr/bin/env ruby -# -$:.unshift '../lib' if __FILE__ == $0 # Make this library first! - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::ContextChange) - diffs.map do |chunks| - if klass == Diff::LCS::ContextChange - klass.from_a(chunks) - else - chunks.map { |changes| klass.from_a(changes) } - end - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_element - @matched_b << event.new_element - end - - def discard_b(event) - @discards_b << event.new_element - end - - def discard_a(event) - @discards_a << event.old_element - end - - def finished_a(event) - @done_a << [event.old_element, event.old_position] - end - - def finished_b(event) - @done_b << [event.new_element, event.new_position] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_position}#{event.new_position} " - end - - def discard_a(event) - @result << "DA#{event.old_position}#{event.new_position} " - end - - def discard_b(event) - @result << "DB#{event.old_position}#{event.new_position} " - end - - def change(event) - @result << "C#{event.old_position}#{event.new_position} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ '=', [ 0, 'abc' ], [ 0, 'abc' ] ], - [ '!', [ 1, 'def' ], [ 1, 'dxf' ] ], - [ '-', [ 2, 'yyy' ], [ 2, nil ] ], - [ '=', [ 3, 'xxx' ], [ 2, 'xxx' ] ], - [ '=', [ 4, 'ghi' ], [ 3, 'ghi' ] ], - [ '=', [ 5, 'jkl' ], [ 4, 'jkl' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '=', [ 1, 'b' ], [ 0, 'b' ] ], - [ '=', [ 2, 'c' ], [ 1, 'c' ] ], - [ '+', [ 3, nil ], [ 2, 'd' ] ], - [ '=', [ 3, 'e' ], [ 3, 'e' ] ], - [ '!', [ 4, 'h' ], [ 4, 'f' ] ], - [ '=', [ 5, 'j' ], [ 5, 'j' ] ], - [ '+', [ 6, nil ], [ 6, 'k' ] ], - [ '=', [ 6, 'l' ], [ 7, 'l' ] ], - [ '=', [ 7, 'm' ], [ 8, 'm' ] ], - [ '!', [ 8, 'n' ], [ 9, 'r' ] ], - [ '!', [ 9, 'p' ], [ 10, 's' ] ], - [ '+', [ 10, nil ], [ 11, 't' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ], - [ '-', [ 3, 'd' ], [ 1, nil ] ], - [ '=', [ 4, 'e' ], [ 1, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '+', [ 1, nil ], [ 1, 'b' ] ], - [ '+', [ 1, nil ], [ 2, 'c' ] ], - [ '+', [ 1, nil ], [ 3, 'd' ] ], - [ '=', [ 1, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', [ 0, 'v' ], [ 0, 'w' ] ], - [ '!', [ 1, 'x' ], [ 1, 'y' ] ], - [ '=', [ 2, 'a' ], [ 2, 'a' ] ], - [ '+', [ 3, nil ], [ 3, 'b' ] ], - [ '+', [ 3, nil ], [ 4, 'c' ] ], - [ '+', [ 3, nil ], [ 5, 'd' ] ], - [ '=', [ 3, 'e' ], [ 6, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', [ 0, 'x' ], [ 0, nil ] ], - [ '=', [ 1, 'a' ], [ 0, 'a' ] ], - [ '+', [ 2, nil ], [ 1, 'b' ] ], - [ '+', [ 2, nil ], [ 2, 'c' ] ], - [ '+', [ 2, nil ], [ 3, 'd' ] ], - [ '=', [ 2, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ], - [ '!', [ 2, 'v' ], [ 6, 'w' ] ], - [ '+', [ 3, nil ], [ 7, 'x' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'a' ] ], - [ '+', [ 0, nil ], [ 1, 'b' ] ], - [ '+', [ 0, nil ], [ 2, 'c' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '-', [ 2, 'c' ], [ 0, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', [ 0, 'a' ], [ 0, '1' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '=', [ 2, 'c' ], [ 0, 'c' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', [ 0, 'abcd' ], [ 0, nil ] ], - [ '-', [ 1, 'efgh' ], [ 0, nil ] ], - [ '-', [ 2, 'ijkl' ], [ 0, nil ] ], - [ '-', [ 3, 'mnop' ], [ 0, nil ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'abcd' ] ], - [ '+', [ 0, nil ], [ 1, 'efgh' ] ], - [ '+', [ 0, nil ], [ 2, 'ijkl' ] ], - [ '+', [ 0, nil ], [ 3, 'mnop' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end - -class TestPatching < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_patch_diff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms2 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::SDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end - - def test_patch_sdiff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::DiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end -end diff --git a/diff-lcs/tags/release-1.1.1/ChangeLog b/diff-lcs/tags/release-1.1.1/ChangeLog deleted file mode 100644 index 9285da7..0000000 --- a/diff-lcs/tags/release-1.1.1/ChangeLog +++ /dev/null @@ -1,42 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.1.1 -* Fixed bug #891: - http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 -* Fixed a problem with callback initialisation code (it assumed that all - callbacks passed as classes can be initialised; now, it rescues - NoMethodError in the event of private :new being called). -* Modified the non-initialisable callbacks to have a private #new method. -* Moved ldiff core code to Diff::LCS::Ldiff (diff/lcs/ldiff.rb). - -== Diff::LCS 1.1.0 -* Eliminated the need for Diff::LCS::Event and removed it. -* Added a contextual diff callback, Diff::LCS::ContextDiffCallback. -* Implemented patching/unpatching for standard Diff callback output formats - with both #diff and #sdiff. -* Extensive documentation changes. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/tags/release-1.1.1/Install b/diff-lcs/tags/release-1.1.1/Install deleted file mode 100644 index 016f2ce..0000000 --- a/diff-lcs/tags/release-1.1.1/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.1.1.gem from the usual sources. diff --git a/diff-lcs/tags/release-1.1.1/README b/diff-lcs/tags/release-1.1.1/README deleted file mode 100644 index f2b9e02..0000000 --- a/diff-lcs/tags/release-1.1.1/README +++ /dev/null @@ -1,77 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.1.1, fixing a reported #patch bug in 1.1.0. -Version 1.1.0 added new features, including the ability to #patch and -#unpatch changes as well as a new contextual diff callback, -Diff::LCS::ContextDiffCallbacks, that should improve the context -sensitivity of patching. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - seq2 == Diff::LCS.patch!(seq1, diffs) - seq1 == Diff::LCS.unpatch!(seq2, diffs) - seq2 == Diff::LCS.patch!(seq1, sdiff) - seq1 == Diff::LCS.unpatch!(seq2, sdiff) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - seq2 == seq1.patch!(diffs) - seq1 == seq2.unpatch!(diffs) - seq2 == seq1.patch!(sdiff) - seq1 == seq2.unpatch!(sdiff) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/tags/release-1.1.1/Rakefile b/diff-lcs/tags/release-1.1.1/Rakefile deleted file mode 100644 index b4a277e..0000000 --- a/diff-lcs/tags/release-1.1.1/Rakefile +++ /dev/null @@ -1,103 +0,0 @@ -#! /usr/bin/env rake -$LOAD_PATH.unshift('lib') - -require 'rubygems' -require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' -require 'diff/lcs' -require 'archive/tar/minitar' -require 'zlib' - -DISTDIR = "diff-lcs-#{Diff::LCS::VERSION}" -TARDIST = "../#{DISTDIR}.tar.gz" - -DATE_RE = %r<(\d{4})[./-]?(\d{2})[./-]?(\d{2})(?:[\sT]?(\d{2})[:.]?(\d{2})[:.]?(\d{2})?)?> - -if ENV['RELEASE_DATE'] - year, month, day, hour, minute, second = DATE_RE.match(ENV['RELEASE_DATE']).captures - year ||= 0 - month ||= 0 - day ||= 0 - hour ||= 0 - minute ||= 0 - second ||= 0 - ReleaseDate = Time.mktime(year, month, day, hour, minute, second) -else - ReleaseDate = nil -end - -task :test do |t| - require 'test/unit/testsuite' - require 'test/unit/ui/console/testrunner' - - runner = Test::Unit::UI::Console::TestRunner - - $LOAD_PATH.unshift('tests') - $stderr.puts "Checking for test cases:" if t.verbose - Dir['tests/*test*.rb'].each do |testcase| - $stderr.puts "\t#{testcase}" if t.verbose - load testcase - end - - suite = Test::Unit::TestSuite.new - - ObjectSpace.each_object(Class) do |testcase| - suite << testcase.suite if testcase < Test::Unit::TestCase - end - - runner.run(suite) -end - -spec = eval(File.read("diff-lcs.gemspec")) -desc "Build the RubyGem for Diff::LCS." -task :gem => [ :test ] -Rake::GemPackageTask.new(spec) do |g| - g.need_tar = false - g.need_zip = false - g.package_dir = ".." -end - -desc "Build an Diff::LCS .tar.gz distribution." -task :tar => [ TARDIST ] -file TARDIST => [ :test ] do |t| - current = File.basename(Dir.pwd) - Dir.chdir("..") do - begin - files = Dir["#{current}/**/*"].select { |dd| dd !~ %r{(?:/CVS/?|~$)} } - files.map! do |dd| - ddnew = dd.gsub(/^#{current}/, DISTDIR) - mtime = ReleaseDate || File.stat(dd).mtime - if File.directory?(dd) - { :name => ddnew, :mode => 0555, :dir => true, :mtime => mtime } - else - if dd =~ %r{bin/} - mode = 0755 - else - mode = 0644 - end - data = File.read(dd) - { :name => ddnew, :mode => mode, :data => data, :size => data.size, - :mtime => mtime } - end - end - - ff = File.open(t.name.gsub(%r{^\.\./}o, ''), "wb") - gz = Zlib::GzipWriter.new(ff) - tw = Archive::Tar::Minitar::Writer.new(gz) - - files.each do |entry| - if entry[:dir] - tw.mkdir(entry[:name], entry) - else - tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) } - end - end - ensure - tw.close if tw - gz.close if gz - end - end -end - -desc "Build everything." -task :default => [ :tar, :gem ] diff --git a/diff-lcs/tags/release-1.1.1/diff-lcs.gemspec b/diff-lcs/tags/release-1.1.1/diff-lcs.gemspec deleted file mode 100644 index 26d2b55..0000000 --- a/diff-lcs/tags/release-1.1.1/diff-lcs.gemspec +++ /dev/null @@ -1,40 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.1.1} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - - s.test_files = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/tags/release-1.1.1/htmldiff b/diff-lcs/tags/release-1.1.1/htmldiff deleted file mode 100644 index 8fe23e0..0000000 --- a/diff-lcs/tags/release-1.1.1/htmldiff +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env 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$ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.1.1" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_el}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_el}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs.rb deleted file mode 100644 index 78fe1cd..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs.rb +++ /dev/null @@ -1,1105 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.1.1 - # Computes "intelligent" differences between two sequenced Enumerables. - # This is an implementation of the McIlroy-Hunt "diff" algorithm for - # Enumerable objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version - # (1.2, 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # seq2 == Diff::LCS.patch(seq1, diffs) - # seq2 == Diff::LCS.patch!(seq1, diffs) - # seq1 == Diff::LCS.unpatch(seq2, diffs) - # seq1 == Diff::LCS.unpatch!(seq2, diffs) - # seq2 == Diff::LCS.patch(seq1, sdiff) - # seq2 == Diff::LCS.patch!(seq1, sdiff) - # seq1 == Diff::LCS.unpatch(seq2, sdiff) - # seq1 == Diff::LCS.unpatch!(seq2, sdiff) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = seq1.traverse_sequences(seq2, callback_obj) - # bal = seq1.traverse_balanced(seq2, callback_obj) - # seq2 == seq1.patch(diffs) - # seq2 == seq1.patch!(diffs) - # seq1 == seq2.unpatch(diffs) - # seq1 == seq2.unpatch!(diffs) - # seq2 == seq1.patch(sdiff) - # seq2 == seq1.patch!(sdiff) - # seq1 == seq2.unpatch(sdiff) - # seq1 == seq2.unpatch!(sdiff) - # - # Default extensions are provided for Array and String objects through - # the use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # - # <em>The following text is from the Perl documentation. The only - # changes have been to make the text appear better in Rdoc</em>. - # - # I once read an article written by the authors of +diff+; they said - # that they hard worked very hard on the algorithm until they found the - # right one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the second sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. Documentation includes work by Mark-Jason Dominus. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written originally by Mark-Jason - # Dominus <mjd-perl-diff@plover.com> and later by Ned Konz. The basic Ruby - # implementation was re-ported from the Smalltalk implementation, available - # at ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # #sdiff and #traverse_balanced were written for the Perl version by Mike - # Schilli <m@perlmeister.com>. - # - # "The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed." - module LCS - VERSION = '1.1.1' - end -end - -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns an Array containing the longest common subsequence(s) between - # +self+ and +other+. See Diff::LCS#LCS. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - # Returns the difference set between +self+ and +other+. See - # Diff::LCS#diff. - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - # Returns the balanced ("side-by-side") difference set between +self+ and - # +other+. See Diff::LCS#sdiff. - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+. See Diff::LCS#traverse_sequences. - def traverse_sequences(other, callbacks = nil, &block) - traverse_sequences(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+ using the alternate, balanced algorithm. See - # Diff::LCS#traverse_balanced. - def traverse_balanced(other, callbacks = nil, &block) - traverse_balanced(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Attempts to patch a copy of +self+ with the provided +patchset+. See - # Diff::LCS#patch. - def patch(patchset) - Diff::LCS::patch(self.dup, patchset) - end - - # Attempts to unpatch a copy of +self+ with the provided +patchset+. - # See Diff::LCS#patch. - def unpatch(patchset) - Diff::LCS::unpatch(self.dup, patchset) - end - - # Attempts to patch +self+ with the provided +patchset+. See - # Diff::LCS#patch!. Does no autodiscovery. - def patch!(patchset) - Diff::LCS::patch!(self, patchset) - end - - # Attempts to unpatch +self+ with the provided +patchset+. See - # Diff::LCS#unpatch. Does no autodiscovery. - def unpatch!(patchset) - Diff::LCS::unpatch!(self, patchset) - end -end - -module Diff::LCS - class << self - # Given two sequenced Enumerables, LCS returns an Array containing their - # longest common subsequences. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # - # This array whose contents is such that: - # - # lcs.each_with_index do |ee, ii| - # assert(ee.nil? || (seq1[ii] == seq2[ee])) - # end - # - # If a block is provided, the matching subsequences will be yielded from - # +seq1+ in turn and may be modified before they are placed into the - # returned Array of subsequences. - def LCS(seq1, seq2, &block) #:yields seq1[ii] for each matched: - matches = Diff::LCS.__lcs(seq1, seq2) - ret = [] - matches.each_with_index do |ee, ii| - unless matches[ii].nil? - if block_given? - ret << (yield seq1[ii]) - else - ret << seq1[ii] - end - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. - # - # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. - # If a Class argument is provided for +callbacks+, #diff will attempt - # to initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes: - callbacks ||= Diff::LCS::DiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_sequences(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # old < - - # same same - # before | after - # - > new - # - # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If - # a Class argument is provided for +callbacks+, #diff will attempt to - # initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes: - callbacks ||= Diff::LCS::SDiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_balanced(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # The arguments to #traverse_sequences are the two sequences to - # traverse, and a callback object, like this: - # - # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #diff is implemented with #traverse_sequences. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#finished_a</em>:: Called when +a+ has reached the end of - # sequence +A+. - # <em>callbacks#finished_b</em>:: Called when +b+ has reached the end of - # sequence +B+. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, depending - # on which arrow it advanced. If both arrows point to elements that are - # not part of the longest common subsequence, then #traverse_sequences - # will advance one of them and call the appropriate callback, but it is - # not specified which it will call. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # and <tt>callbacks#discard_b</tt> are invoked with an event comprising - # the action ("=", "+", or "-", respectively), the indicies +ii+ and - # +jj+, and the elements <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return - # values are discarded by #traverse_sequences. - # - # === End of Sequences - # If arrow +a+ reaches the end of its sequence before arrow +b+ does, - # #traverse_sequence try to call <tt>callbacks#finished_a</tt> with the - # last index and element of +A+ (<tt>A[-1]</tt>) and the current index - # and element of +B+ (<tt>B[jj]</tt>). If <tt>callbacks#finished_a</tt> - # does not exist, then <tt>callbacks#discard_b</tt> will be called on - # each element of +B+ until the end of the sequence is reached (the call - # will be done with <tt>A[-1]</tt> and <tt>B[jj]</tt> for each element). - # - # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+, - # <tt>callbacks#finished_b</tt> will be called with the current index - # and element of +A+ (<tt>A[ii]</tt>) and the last index and element of - # +B+ (<tt>A[-1]</tt>). Again, if <tt>callbacks#finished_b</tt> does not - # exist on the callback object, then <tt>callbacks#discard_a</tt> will - # be called on each element of +A+ until the end of the sequence is - # reached (<tt>A[ii]</tt> and <tt>B[-1]</tt>). - # - # There is a chance that one additional <tt>callbacks#discard_a</tt> or - # <tt>callbacks#discard_b</tt> will be called after the end of the - # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+ - # has not yet reached the end of +B+. - def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events: - matches = Diff::LCS.__lcs(seq1, seq2) - - run_finished_a = run_finished_b = false - string = seq1.kind_of?(String) - - a_size = seq1.size - b_size = seq2.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? seq1[ii, 1] : seq1[ii] - bx = string ? seq2[bj, 1] : seq2[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::ContextChange.new('-', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? seq1[-1, 1] : seq1[-1] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx) - event = yield event if block_given? - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? seq1[ai, 1] : seq1[ai] - loop do - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[-1, 1] : seq2[-1] - event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx) - event = yield event if block_given? - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? seq2[bj, 1] : seq2[bj] - loop do - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - # #traverse_balanced is an alternative to #traverse_sequences. It - # uses a different algorithm to iterate through the entries in the - # computed longest common subsequence. Instead of viewing the changes as - # insertions or deletions from one of the sequences, #traverse_balanced - # will report <em>changes</em> between the sequences. To represent a - # - # The arguments to #traverse_balanced are the two sequences to traverse - # and a callback object, like this: - # - # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #sdiff is implemented with #traverse_balanced. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#change</em>:: Called when +a+ and +b+ are pointing - # to the same relative position, but - # <tt>A[a]</tt> and <tt>B[b]</tt> are - # not the same; a <em>change</em> has - # occurred. - # - # #traverse_balanced might be a bit slower than #traverse_sequences, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # #traverse_balanced. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # === Matches - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # === Discards - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, - # depending on which arrow it advanced. - # - # === Changes - # If both +a+ and +b+ point to elements that are not part of the longest - # common subsequence, then #traverse_sequences will try to call - # <tt>callbacks#change</tt> and advance both arrows. If - # <tt>callbacks#change</tt> is not implemented, then - # <tt>callbacks#discard_a</tt> and <tt>callbacks#discard_b</tt> will be - # called in turn. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # <tt>callbacks#discard_b</tt>, and <tt>callbacks#change</tt> are - # invoked with an event comprising the action ("=", "+", "-", or "!", - # respectively), the indicies +ii+ and +jj+, and the elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return values are discarded by - # #traverse_balanced. - # - # === Context - # Note that +ii+ and +jj+ may not be the same index position, even if - # +a+ and +b+ are considered to be pointing to matching or changed - # elements. - def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(seq1, seq2) - a_size = seq1.size - b_size = seq2.size - ai = bj = mb = 0 - ma = -1 - string = seq1.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(seq2) - while (ai < ma) or (bj < mb) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - PATCH_MAP = { #:nodoc: - :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }, - :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' } - } - - # Given a patchset, convert the current version to the new - # version. If +direction+ is not specified (must be - # <tt>:patch</tt> or <tt>:unpatch</tt>), then discovery of the - # direction of the patch will be attempted. - def patch(src, patchset, direction = nil) - string = src.kind_of?(String) - # Start with a new empty type of the source's class - res = src.class.new - - # Normalize the patchset. - patchset = __normalize_patchset(patchset) - - direction ||= Diff::LCS.__diff_direction(src, patchset) - direction ||= :patch - - ai = bj = 0 - - patchset.each do |change| - # Both Change and ContextChange support #action - action = PATCH_MAP[direction][change.action] - - case change - when Diff::LCS::ContextChange - case direction - when :patch - el = change.new_element - op = change.old_position - np = change.new_position - when :unpatch - el = change.old_element - op = change.new_position - np = change.old_position - end - - case action - when '-' # Remove details from the old string - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < np - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res << el - bj += 1 - when '=' - # This only appears in sdiff output with the SDiff callback. - # Therefore, we only need to worry about dealing with a single - # element. - res << el - - ai += 1 - bj += 1 - when '!' - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - ai += 1 - - res << el - end - when Diff::LCS::Change - case action - when '-' - while ai < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - - res << change.element - end - end - end - - while ai < src.size - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res - end - - # Given a set of patchset, convert the current version to the prior - # version. Does no auto-discovery. - def unpatch!(src, patchset) - Diff::LCS.patch(src, patchset, :unpatch) - end - - # Given a set of patchset, convert the current version to the next - # version. Does no auto-discovery. - def patch!(src, patchset) - Diff::LCS.patch(src, patchset, :patch) - end - -# private - # Compute the longest common subsequence between the sequenced Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. (Currently unused.) - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Examine the patchset and the source to see in which direction the - # patch should be applied. - # - # WARNING: By default, this examines the whole patch, so this could take - # some time. This also works better with Diff::LCS::ContextChange or - # Diff::LCS::Change as its source, as an array will cause the creation - # of one of the above. - def __diff_direction(src, patchset, limit = nil) - count = left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - patchset.each do |change| - count += 1 - - case change - when Diff::LCS::Change - # With a simplistic change, we can't tell the difference between - # the left and right on '!' actions, so we ignore those. On '=' - # actions, if there's a miss, we miss both left and right. - element = string ? src[change.position, 1] : src[change.position] - - case change.action - when '-' - if element == change.element - left += 1 - else - left_miss += 1 - end - when '+' - if element == change.element - right += 1 - else - right_miss += 1 - end - when '=' - if element != change.element - left_miss += 1 - right_miss += 1 - end - end - when Diff::LCS::ContextChange - case change.action - when '-' # Remove details from the old string - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - left_miss += 1 - end - when '+' - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - right_miss += 1 - end - when '=' - le = string ? src[change.old_position, 1] : src[change.old_position] - re = string ? src[change.new_position, 1] : src[change.new_position] - - left_miss += 1 if le != change.old_element - right_miss += 1 if re != change.new_element - when '!' - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - left_miss += 1 - right_miss += 1 - end - end - end - end - - break if not limit.nil? and count > limit - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided patchset does not appear to apply to the provided value as either source or destination value." - end - end - - # Normalize the patchset. A patchset is always a sequence of changes, but - # how those changes are represented may vary, depending on how they were - # generated. In all cases we support, we also support the array - # representation of the changes. The formats are: - # - # [ # patchset <- Diff::LCS.diff(a, b) - # [ # one or more hunks - # Diff::LCS::Change # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, line, value ] # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.diff(a, b, Diff::LCS::ContextDiffCallbacks) - # # OR <- Diff::LCS.sdiff(a, b, Diff::LCS::ContextDiffCallbacks) - # [ # one or more hunks - # Diff::LCS::ContextChange # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.sdiff(a, b) - # # OR <- Diff::LCS.diff(a, b, Diff::LCS::SDiffCallbacks) - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset, equivalent to the above - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] - # - # The result of this will be either of the following. - # - # [ # patchset - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset - # Diff::LCS::Change # one or more changes - # ] - # - # If either of the above is provided, it will be returned as such. - # - def __normalize_patchset(patchset) - patchset.map do |hunk| - case hunk - when Diff::LCS::ContextChange, Diff::LCS::Change - hunk - when Array - if (not hunk[0].kind_of?(Array)) and hunk[1].kind_of?(Array) and hunk[2].kind_of?(Array) - Diff::LCS::ContextChange.from_a(hunk) - else - hunk.map do |change| - case change - when Diff::LCS::ContextChange, Diff::LCS::Change - change - when Array - # change[1] will ONLY be an array in a ContextChange#to_a call. - # In Change#to_a, it represents the line (singular). - if change[1].kind_of?(Array) - Diff::LCS::ContextChange.from_a(change) - else - Diff::LCS::Change.from_a(change) - end - end - end - end - else - raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}." - end - end.flatten - end - end -end diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs/array.rb deleted file mode 100644 index e07f8aa..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/array.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into the Array built-in class. - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs/block.rb deleted file mode 100644 index 7dceb48..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/block.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Block for bin/ldiff. - - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/ldiff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else # [true, true] - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs/change.rb deleted file mode 100644 index 6ecdf7e..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/change.rb +++ /dev/null @@ -1,169 +0,0 @@ -#! /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$ -#++ -# 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 diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs/hunk.rb deleted file mode 100644 index 58fac9f..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,257 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Hunk for bin/ldiff. - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.1.1/lib/diff/lcs/string.rb deleted file mode 100644 index 2de7d1f..0000000 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/string.rb +++ /dev/null @@ -1,19 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into String. - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.1.2/Rakefile b/diff-lcs/tags/release-1.1.2/Rakefile deleted file mode 100644 index 6a2f963..0000000 --- a/diff-lcs/tags/release-1.1.2/Rakefile +++ /dev/null @@ -1,116 +0,0 @@ -#! /usr/bin/env rake -$LOAD_PATH.unshift('lib') - -require 'rubygems' -require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' -require 'diff/lcs' -require 'archive/tar/minitar' -require 'zlib' - -DISTDIR = "diff-lcs-#{Diff::LCS::VERSION}" -TARDIST = "../#{DISTDIR}.tar.gz" - -DATE_RE = %r<(\d{4})[./-]?(\d{2})[./-]?(\d{2})(?:[\sT]?(\d{2})[:.]?(\d{2})[:.]?(\d{2})?)?> - -if ENV['RELEASE_DATE'] - year, month, day, hour, minute, second = DATE_RE.match(ENV['RELEASE_DATE']).captures - year ||= 0 - month ||= 0 - day ||= 0 - hour ||= 0 - minute ||= 0 - second ||= 0 - ReleaseDate = Time.mktime(year, month, day, hour, minute, second) -else - ReleaseDate = nil -end - -task :test do |t| - require 'test/unit/testsuite' - require 'test/unit/ui/console/testrunner' - - runner = Test::Unit::UI::Console::TestRunner - - $LOAD_PATH.unshift('tests') - $stderr.puts "Checking for test cases:" if t.verbose - Dir['tests/*test*.rb'].each do |testcase| - $stderr.puts "\t#{testcase}" if t.verbose - load testcase - end - - suite = Test::Unit::TestSuite.new - - ObjectSpace.each_object(Class) do |testcase| - suite << testcase.suite if testcase < Test::Unit::TestCase - end - - runner.run(suite) -end - -spec = eval(File.read("diff-lcs.gemspec")) -desc "Build the RubyGem for Diff::LCS." -task :gem => [ :test ] -Rake::GemPackageTask.new(spec) do |g| - g.need_tar = false - g.need_zip = false - g.package_dir = ".." -end - -desc "Build an Diff::LCS .tar.gz distribution." -task :tar => [ TARDIST ] -file TARDIST => [ :test ] do |t| - current = File.basename(Dir.pwd) - Dir.chdir("..") do - begin - files = Dir["#{current}/**/*"].select { |dd| dd !~ %r{(?:/CVS/?|~$)} } - files.map! do |dd| - ddnew = dd.gsub(/^#{current}/, DISTDIR) - mtime = ReleaseDate || File.stat(dd).mtime - if File.directory?(dd) - { :name => ddnew, :mode => 0755, :dir => true, :mtime => mtime } - else - if dd =~ %r{bin/} - mode = 0755 - else - mode = 0644 - end - data = File.read(dd) - { :name => ddnew, :mode => mode, :data => data, :size => data.size, - :mtime => mtime } - end - end - - ff = File.open(t.name.gsub(%r{^\.\./}o, ''), "wb") - gz = Zlib::GzipWriter.new(ff) - tw = Archive::Tar::Minitar::Writer.new(gz) - - files.each do |entry| - if entry[:dir] - tw.mkdir(entry[:name], entry) - else - tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) } - end - end - ensure - tw.close if tw - gz.close if gz - end - end -end -task TARDIST => [ :test ] - -def sign(file) - sh %("C:\\Program Files\\Windows Privacy Tools\\GnuPG\\Gpg.exe" -ba #{file}) -end - -task :signtar => [ :tar ] do - sign TARDIST -end -task :signgem => [ :gem ] do - sign "../#{DISTDIR}.gem" -end - -desc "Build everything." -task :default => [ :signtar, :signgem ] do -end diff --git a/diff-lcs/tags/release-1.1.2/install.rb b/diff-lcs/tags/release-1.1.2/install.rb deleted file mode 100644 index 4bd3d7a..0000000 --- a/diff-lcs/tags/release-1.1.2/install.rb +++ /dev/null @@ -1,262 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = Test::Unit::TestSuite.new - ObjectSpace.each_object(Class) { |o| tests << o.suite if o < Test::Unit::TestCase } - - Test::Unit::UI::Console::TestRunner.run(tests) - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/tags/release-1.1.2/ldiff b/diff-lcs/tags/release-1.1.2/ldiff deleted file mode 100644 index ae2b245..0000000 --- a/diff-lcs/tags/release-1.1.2/ldiff +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env 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$ -#++ - - # 1) Try to load Ruwiki from the gem. - # 2) Try to load Ruwiki from $LOAD_PATH. - # 3) Modify $LOAD_PATH and try to load it from the modified $LOAD_PATH. - # 4) Fail hard. -load_state = 1 - begin - if 1 == load_state - require 'rubygems' - require_gem 'diff-lcs', '= 1.1.1' - else - require 'diff/lcs' - end - rescue LoadError - load_state += 1 - - case load_state - when 3 - $LOAD_PATH.unshift "#{File.dirname($0)}/../lib" - when 4 - $LOAD_PATH.shift - $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" - when 5 - raise - end - retry - end - -require 'diff/lcs/ldiff' - -exit Diff::LCS::Ldiff.run(ARGV) diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/array.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/array.rb deleted file mode 100644 index e07f8aa..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/array.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into the Array built-in class. - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/block.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/block.rb deleted file mode 100644 index 7dceb48..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/block.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Block for bin/ldiff. - - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/ldiff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else # [true, true] - '^' - end - end -end diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/callbacks.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/callbacks.rb deleted file mode 100644 index 74a1cdc..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,322 +0,0 @@ -#! /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$ -#++ -# Contains definitions for all default callback objects. - -require 'diff/lcs/change' - -module Diff::LCS - # This callback object implements the default set of callback events, which - # only returns the event itself. Note that #finished_a and #finished_b are - # not implemented -- I haven't yet figured out where they would be useful. - # - # Note that this is intended to be called as is, e.g., - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks) - class DefaultCallbacks - class << self - # Called when two items match. - def match(event) - event - end - # Called when the old value is discarded in favour of the new value. - def discard_a(event) - event - end - # Called when the new value is discarded in favour of the old value. - def discard_b(event) - event - end - # Called when both the old and new values have changed. - def change(event) - event - end - - private :new - end - end - - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_sequences. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks) - SequenceCallbacks = DefaultCallbacks - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_balanced. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks) - BalancedCallbacks = DefaultCallbacks -end - - # This will produce a compound array of simple diff change objects. Each - # element in the #diffs array is a +hunk+ or +hunk+ array, where each - # element in each +hunk+ array is a single Change object representing the - # addition or removal of a single element from one of the two tested - # sequences. The +hunk+ provides the full context for the changes. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ [ '-', 0, 'a' ] ], # 1 - # # [ [ '+', 2, 'd' ] ], # 2 - # # [ [ '-', 4, 'h' ], # 3 - # # [ '+', 4, 'f' ] ], - # # [ [ '+', 6, 'k' ] ], # 4 - # # [ [ '-', 8, 'n' ], # 5 - # # [ '-', 9, 'p' ], - # # [ '+', 9, 'r' ], - # # [ '+', 10, 's' ], - # # [ '+', 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at position 0 - # of the first sequence should be deleted (<tt>'-'</tt>). The second hunk - # says that the +d+ at position 2 of the second sequence should be inserted - # (<tt>'+'</tt>). The third hunk says that the +h+ at position 4 of the - # first sequence should be removed and replaced with the +f+ from position 4 - # of the second sequence. The other two hunks are described similarly. - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#diff - # method. - # - # cbo = Diff::LCS::DiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::DiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize # :yields self: - @hunk = [] - @diffs = [] - - if block_given? - begin - yield self - ensure - self.finish - end - end - end - - # Finalizes the diff process. If an unprocessed hunk still exists, then it - # is appended to the diff list. - def finish - add_nonempty_hunk - end - - def match(event) - add_nonempty_hunk - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_position, event.old_element) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_position, event.new_element) - end - -private - def add_nonempty_hunk - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end -end - - # This will produce a compound array of contextual diff change objects. Each - # element in the #diffs array is a "hunk" array, where each element in each - # "hunk" array is a single change. Each change is a Diff::LCS::ContextChange - # that contains both the old index and new index values for the change. The - # "hunk" provides the full context for the changes. Both old and new objects - # will be presented for changed objects. +nil+ will be substituted for a - # discarded object. - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks) - # # This example shows a simplified array format. - # # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1 - # # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2 - # # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3 - # # [ '+', [ 5, nil ], [ 4, 'f' ] ] ], - # # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4 - # # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5 - # # [ '+', [ 9, nil ], [ 9, 'r' ] ], - # # [ '-', [ 9, 'p' ], [ 10, nil ] ], - # # [ '+', [ 10, nil ], [ 10, 's' ] ], - # # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ] - # - # The five hunks shown are comprised of individual changes; if there is a - # related set of changes, they are still shown individually. - # - # This callback can also be used with Diff::LCS#sdiff, which will produce - # results like: - # - # diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks) - # # This example shows a simplified array format. - # # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1 - # # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2 - # # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3 - # # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4 - # # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5 - # # [ "!", [ 9, "p" ], [ 10, "s" ] ], - # # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ] - # - # The five hunks are still present, but are significantly shorter in total - # presentation, because changed items are shown as changes ("!") instead of - # potentially "mismatched" pairs of additions and deletions. - # - # The result of this operation is similar to that of - # Diff::LCS::SDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and can be used by the - # Diff::LCS#diff or Diff::LCS#sdiff methods. - # - # cbo = Diff::LCS::ContextDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::ContextDiffCallbacks < Diff::LCS::DiffCallbacks - def discard_a(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end -end - - # This will produce a simple array of diff change objects. Each element in - # the #diffs array is a single ContextChange. In the set of #diffs provided - # by SDiffCallbacks, both old and new objects will be presented for both - # changed <strong>and unchanged</strong> objects. +nil+ will be substituted - # for a discarded object. - # - # The diffset produced by this callback, when provided to Diff::LCS#sdiff, - # will compute and display the necessary components to show two sequences - # and their minimized differences side by side, just like the Unix utility - # +sdiff+. - # - # same same - # before | after - # old < - - # - > new - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.sdiff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ "-", [ 0, "a"], [ 0, nil ] ], - # # [ "=", [ 1, "b"], [ 0, "b" ] ], - # # [ "=", [ 2, "c"], [ 1, "c" ] ], - # # [ "+", [ 3, nil], [ 2, "d" ] ], - # # [ "=", [ 3, "e"], [ 3, "e" ] ], - # # [ "!", [ 4, "h"], [ 4, "f" ] ], - # # [ "=", [ 5, "j"], [ 5, "j" ] ], - # # [ "+", [ 6, nil], [ 6, "k" ] ], - # # [ "=", [ 6, "l"], [ 7, "l" ] ], - # # [ "=", [ 7, "m"], [ 8, "m" ] ], - # # [ "!", [ 8, "n"], [ 9, "r" ] ], - # # [ "!", [ 9, "p"], [ 10, "s" ] ], - # # [ "+", [ 10, nil], [ 11, "t" ] ] ] - # - # The result of this operation is similar to that of - # Diff::LCS::ContextDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#sdiff - # method. - # - # cbo = Diff::LCS::SDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # - # As with the other initialisable callback objects, Diff::LCS::SDiffCallbacks - # can be initialised with a block. As there is no "fininishing" to be done, - # this has no effect on the state of the object. - # - # cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.to_a } -class Diff::LCS::SDiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize #:yields self: - @diffs = [] - yield self if block_given? - end - - def match(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_a(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end -end diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/change.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/change.rb deleted file mode 100644 index 6ecdf7e..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/change.rb +++ /dev/null @@ -1,169 +0,0 @@ -#! /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$ -#++ -# 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 diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/hunk.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/hunk.rb deleted file mode 100644 index 58fac9f..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,257 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Hunk for bin/ldiff. - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/ldiff.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/ldiff.rb deleted file mode 100644 index 61abc47..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/ldiff.rb +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require 'ostruct' -require 'diff/lcs/hunk' - - # == ldiff Usage - # ldiff [options] oldfile newfile - # - # -c:: Displays a context diff with 3 lines of context. - # -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. - # -u:: Displays a unified diff with 3 lines of context. - # -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. - # -e:: Creates an 'ed' script to change oldfile to newfile. - # -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. - # -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. - # --binary:: Treats the files as binary. - # -q, --brief:: Reports only whether or not the files differ, not the details. - # --help:: Shows the command-line help. - # --version:: Shows the version of Diff::LCS. - # - # By default, runs produces an "old-style" diff, with output like UNIX diff. - # - # == Copyright - # Copyright © 2004 Austin Ziegler - # - # Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> - # Austin Ziegler <diff-lcs@halostatue.ca> - # - # 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. -module Diff::LCS::Ldiff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def run(args, input = $stdin, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/string.rb b/diff-lcs/tags/release-1.1.2/lib/diff/lcs/string.rb deleted file mode 100644 index 2de7d1f..0000000 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs/string.rb +++ /dev/null @@ -1,19 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into String. - -class String - include Diff::LCS -end diff --git a/diff-lcs/tags/release-1.1.2/tests/00test.rb b/diff-lcs/tags/release-1.1.2/tests/00test.rb deleted file mode 100644 index 8872dfd..0000000 --- a/diff-lcs/tags/release-1.1.2/tests/00test.rb +++ /dev/null @@ -1,626 +0,0 @@ -#! /usr/bin/env ruby -# -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::ContextChange) - diffs.map do |chunks| - if klass == Diff::LCS::ContextChange - klass.from_a(chunks) - else - chunks.map { |changes| klass.from_a(changes) } - end - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_element - @matched_b << event.new_element - end - - def discard_b(event) - @discards_b << event.new_element - end - - def discard_a(event) - @discards_a << event.old_element - end - - def finished_a(event) - @done_a << [event.old_element, event.old_position] - end - - def finished_b(event) - @done_b << [event.new_element, event.new_position] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_position}#{event.new_position} " - end - - def discard_a(event) - @result << "DA#{event.old_position}#{event.new_position} " - end - - def discard_b(event) - @result << "DB#{event.old_position}#{event.new_position} " - end - - def change(event) - @result << "C#{event.old_position}#{event.new_position} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ '=', [ 0, 'abc' ], [ 0, 'abc' ] ], - [ '!', [ 1, 'def' ], [ 1, 'dxf' ] ], - [ '-', [ 2, 'yyy' ], [ 2, nil ] ], - [ '=', [ 3, 'xxx' ], [ 2, 'xxx' ] ], - [ '=', [ 4, 'ghi' ], [ 3, 'ghi' ] ], - [ '=', [ 5, 'jkl' ], [ 4, 'jkl' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '=', [ 1, 'b' ], [ 0, 'b' ] ], - [ '=', [ 2, 'c' ], [ 1, 'c' ] ], - [ '+', [ 3, nil ], [ 2, 'd' ] ], - [ '=', [ 3, 'e' ], [ 3, 'e' ] ], - [ '!', [ 4, 'h' ], [ 4, 'f' ] ], - [ '=', [ 5, 'j' ], [ 5, 'j' ] ], - [ '+', [ 6, nil ], [ 6, 'k' ] ], - [ '=', [ 6, 'l' ], [ 7, 'l' ] ], - [ '=', [ 7, 'm' ], [ 8, 'm' ] ], - [ '!', [ 8, 'n' ], [ 9, 'r' ] ], - [ '!', [ 9, 'p' ], [ 10, 's' ] ], - [ '+', [ 10, nil ], [ 11, 't' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ], - [ '-', [ 3, 'd' ], [ 1, nil ] ], - [ '=', [ 4, 'e' ], [ 1, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '+', [ 1, nil ], [ 1, 'b' ] ], - [ '+', [ 1, nil ], [ 2, 'c' ] ], - [ '+', [ 1, nil ], [ 3, 'd' ] ], - [ '=', [ 1, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', [ 0, 'v' ], [ 0, 'w' ] ], - [ '!', [ 1, 'x' ], [ 1, 'y' ] ], - [ '=', [ 2, 'a' ], [ 2, 'a' ] ], - [ '+', [ 3, nil ], [ 3, 'b' ] ], - [ '+', [ 3, nil ], [ 4, 'c' ] ], - [ '+', [ 3, nil ], [ 5, 'd' ] ], - [ '=', [ 3, 'e' ], [ 6, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', [ 0, 'x' ], [ 0, nil ] ], - [ '=', [ 1, 'a' ], [ 0, 'a' ] ], - [ '+', [ 2, nil ], [ 1, 'b' ] ], - [ '+', [ 2, nil ], [ 2, 'c' ] ], - [ '+', [ 2, nil ], [ 3, 'd' ] ], - [ '=', [ 2, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ], - [ '!', [ 2, 'v' ], [ 6, 'w' ] ], - [ '+', [ 3, nil ], [ 7, 'x' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'a' ] ], - [ '+', [ 0, nil ], [ 1, 'b' ] ], - [ '+', [ 0, nil ], [ 2, 'c' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '-', [ 2, 'c' ], [ 0, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', [ 0, 'a' ], [ 0, '1' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '=', [ 2, 'c' ], [ 0, 'c' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', [ 0, 'abcd' ], [ 0, nil ] ], - [ '-', [ 1, 'efgh' ], [ 0, nil ] ], - [ '-', [ 2, 'ijkl' ], [ 0, nil ] ], - [ '-', [ 3, 'mnop' ], [ 0, nil ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'abcd' ] ], - [ '+', [ 0, nil ], [ 1, 'efgh' ] ], - [ '+', [ 0, nil ], [ 2, 'ijkl' ] ], - [ '+', [ 0, nil ], [ 3, 'mnop' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end - -class TestPatching < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_patch_diff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms2 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::SDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end - - # Tests patch bug #891: - # http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 - def test_patch_bug891 - s1 = s2 = s3 = s4 = s5 = ps = nil - assert_nothing_raised do - s1 = %w{a b c d e f g h i j k } - s2 = %w{a b c d D e f g h i j k } - ps = Diff::LCS::diff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::SDiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - - assert_nothing_raised do - ps = Diff::LCS::sdiff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::DiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - end - - def test_patch_sdiff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::DiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end -end diff --git a/diff-lcs/trunk/ChangeLog b/diff-lcs/trunk/ChangeLog deleted file mode 100644 index 08d3ee5..0000000 --- a/diff-lcs/trunk/ChangeLog +++ /dev/null @@ -1,46 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler <diff-lcs@halostatue.ca>. - -== Diff::LCS 1.1.2 -* Fixed a problem reported by Mauricio Fernandez in htmldiff. Future versions - of Diff::LCS will be removing this program. - -== Diff::LCS 1.1.1 -* Fixed bug #891: - http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 -* Fixed a problem with callback initialisation code (it assumed that all - callbacks passed as classes can be initialised; now, it rescues - NoMethodError in the event of private :new being called). -* Modified the non-initialisable callbacks to have a private #new method. -* Moved ldiff core code to Diff::LCS::Ldiff (diff/lcs/ldiff.rb). - -== Diff::LCS 1.1.0 -* Eliminated the need for Diff::LCS::Event and removed it. -* Added a contextual diff callback, Diff::LCS::ContextDiffCallback. -* Implemented patching/unpatching for standard Diff callback output formats - with both #diff and #sdiff. -* Extensive documentation changes. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/diff-lcs/trunk/Install b/diff-lcs/trunk/Install deleted file mode 100644 index 794796e..0000000 --- a/diff-lcs/trunk/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.1.2.gem from the usual sources. diff --git a/diff-lcs/trunk/README b/diff-lcs/trunk/README deleted file mode 100644 index 4c9b517..0000000 --- a/diff-lcs/trunk/README +++ /dev/null @@ -1,76 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.1.2, fixing an htmldiff bug in 1.1.1. Version 1.1.0 -added new features, including the ability to #patch and #unpatch changes as -well as a new contextual diff callback, Diff::LCS::ContextDiffCallbacks, that -should improve the context sensitivity of patching. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - seq2 == Diff::LCS.patch!(seq1, diffs) - seq1 == Diff::LCS.unpatch!(seq2, diffs) - seq2 == Diff::LCS.patch!(seq1, sdiff) - seq1 == Diff::LCS.unpatch!(seq2, sdiff) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - seq2 == seq1.patch!(diffs) - seq1 == seq2.unpatch!(diffs) - seq2 == seq1.patch!(sdiff) - seq1 == seq2.unpatch!(sdiff) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# 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$ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/diff-lcs/trunk/bin/htmldiff b/diff-lcs/trunk/bin/htmldiff deleted file mode 100644 index 509860c..0000000 --- a/diff-lcs/trunk/bin/htmldiff +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env 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$ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.1.1" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs' - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|<pre class="match">#{event.old_element}</pre>\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|<pre class="only_a">#{event.old_element}</pre>\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|<pre class="only_b">#{event.new_element}</pre>\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START -<html> - <head> - <title>diff #{ARGV[0]} #{ARGV[1]}</title> - <style> - body { margin: 0; } - .diff - { - border: 1px solid black; - margin: 1em 2em; - } - pre - { - padding-left: 1em; - margin: 0; - font-family: Lucida, Courier, monospaced; - white-space: pre; - } - .match { } - .only_a - { - background-color: #fdd; - color: red; - text-decoration: line-through; - } - .only_b - { - background-color: #ddf; - color: blue; - border-left: 3px solid blue - } - h1 { margin-left: 2em; } - </style> - </head> - <body> - <h1>diff - <span class="only_a">#{ARGV[0]}</span> - <span class="only_b">#{ARGV[1]}</span> - </h1> - <div class="diff"> -START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END - </div> - </body> -</html> -END diff --git a/diff-lcs/trunk/bin/ldiff b/diff-lcs/trunk/bin/ldiff deleted file mode 100644 index ae2b245..0000000 --- a/diff-lcs/trunk/bin/ldiff +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env 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$ -#++ - - # 1) Try to load Ruwiki from the gem. - # 2) Try to load Ruwiki from $LOAD_PATH. - # 3) Modify $LOAD_PATH and try to load it from the modified $LOAD_PATH. - # 4) Fail hard. -load_state = 1 - begin - if 1 == load_state - require 'rubygems' - require_gem 'diff-lcs', '= 1.1.1' - else - require 'diff/lcs' - end - rescue LoadError - load_state += 1 - - case load_state - when 3 - $LOAD_PATH.unshift "#{File.dirname($0)}/../lib" - when 4 - $LOAD_PATH.shift - $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" - when 5 - raise - end - retry - end - -require 'diff/lcs/ldiff' - -exit Diff::LCS::Ldiff.run(ARGV) diff --git a/diff-lcs/trunk/diff-lcs.gemspec b/diff-lcs/trunk/diff-lcs.gemspec deleted file mode 100644 index ba49ed6..0000000 --- a/diff-lcs/trunk/diff-lcs.gemspec +++ /dev/null @@ -1,40 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.1.2} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - - s.test_files = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/diff-lcs/trunk/install.rb b/diff-lcs/trunk/install.rb deleted file mode 100644 index 4bd3d7a..0000000 --- a/diff-lcs/trunk/install.rb +++ /dev/null @@ -1,262 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = Test::Unit::TestSuite.new - ObjectSpace.each_object(Class) { |o| tests << o.suite if o < Test::Unit::TestCase } - - Test::Unit::UI::Console::TestRunner.run(tests) - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/diff-lcs/trunk/lib/diff/lcs.rb b/diff-lcs/trunk/lib/diff/lcs.rb deleted file mode 100644 index b74b2d3..0000000 --- a/diff-lcs/trunk/lib/diff/lcs.rb +++ /dev/null @@ -1,1105 +0,0 @@ -#! /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$ -#++ - -module Diff - # = Diff::LCS 1.1.2 - # Computes "intelligent" differences between two sequenced Enumerables. - # This is an implementation of the McIlroy-Hunt "diff" algorithm for - # Enumerable objects that include Diffable. - # - # Based on Mario I. Wolczko's <mario@wolczko.com> Smalltalk version - # (1.2, 1993) and Ned Konz's <perl@bike-nomad.com> Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # seq2 == Diff::LCS.patch(seq1, diffs) - # seq2 == Diff::LCS.patch!(seq1, diffs) - # seq1 == Diff::LCS.unpatch(seq2, diffs) - # seq1 == Diff::LCS.unpatch!(seq2, diffs) - # seq2 == Diff::LCS.patch(seq1, sdiff) - # seq2 == Diff::LCS.patch!(seq1, sdiff) - # seq1 == Diff::LCS.unpatch(seq2, sdiff) - # seq1 == Diff::LCS.unpatch!(seq2, sdiff) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = seq1.traverse_sequences(seq2, callback_obj) - # bal = seq1.traverse_balanced(seq2, callback_obj) - # seq2 == seq1.patch(diffs) - # seq2 == seq1.patch!(diffs) - # seq1 == seq2.unpatch(diffs) - # seq1 == seq2.unpatch!(diffs) - # seq2 == seq1.patch(sdiff) - # seq2 == seq1.patch!(sdiff) - # seq1 == seq2.unpatch(sdiff) - # seq1 == seq2.unpatch!(sdiff) - # - # Default extensions are provided for Array and String objects through - # the use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # - # <em>The following text is from the Perl documentation. The only - # changes have been to make the text appear better in Rdoc</em>. - # - # I once read an article written by the authors of +diff+; they said - # that they hard worked very hard on the algorithm until they found the - # right one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the second sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # == Author - # This version is by Austin Ziegler <diff-lcs@halostatue.ca>. - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # <perl@bike-nomad.com>, copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko <mario@wolczko.com>, copyright © - # 1993. Documentation includes work by Mark-Jason Dominus. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written originally by Mark-Jason - # Dominus <mjd-perl-diff@plover.com> and later by Ned Konz. The basic Ruby - # implementation was re-ported from the Smalltalk implementation, available - # at ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # #sdiff and #traverse_balanced were written for the Perl version by Mike - # Schilli <m@perlmeister.com>. - # - # "The algorithm is described in <em>A Fast Algorithm for Computing Longest - # Common Subsequences</em>, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed." - module LCS - VERSION = '1.1.2' - end -end - -require 'diff/lcs/callbacks' - -module Diff::LCS - # Returns an Array containing the longest common subsequence(s) between - # +self+ and +other+. See Diff::LCS#LCS. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - # Returns the difference set between +self+ and +other+. See - # Diff::LCS#diff. - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - # Returns the balanced ("side-by-side") difference set between +self+ and - # +other+. See Diff::LCS#sdiff. - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+. See Diff::LCS#traverse_sequences. - def traverse_sequences(other, callbacks = nil, &block) - traverse_sequences(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+ using the alternate, balanced algorithm. See - # Diff::LCS#traverse_balanced. - def traverse_balanced(other, callbacks = nil, &block) - traverse_balanced(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Attempts to patch a copy of +self+ with the provided +patchset+. See - # Diff::LCS#patch. - def patch(patchset) - Diff::LCS::patch(self.dup, patchset) - end - - # Attempts to unpatch a copy of +self+ with the provided +patchset+. - # See Diff::LCS#patch. - def unpatch(patchset) - Diff::LCS::unpatch(self.dup, patchset) - end - - # Attempts to patch +self+ with the provided +patchset+. See - # Diff::LCS#patch!. Does no autodiscovery. - def patch!(patchset) - Diff::LCS::patch!(self, patchset) - end - - # Attempts to unpatch +self+ with the provided +patchset+. See - # Diff::LCS#unpatch. Does no autodiscovery. - def unpatch!(patchset) - Diff::LCS::unpatch!(self, patchset) - end -end - -module Diff::LCS - class << self - # Given two sequenced Enumerables, LCS returns an Array containing their - # longest common subsequences. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # - # This array whose contents is such that: - # - # lcs.each_with_index do |ee, ii| - # assert(ee.nil? || (seq1[ii] == seq2[ee])) - # end - # - # If a block is provided, the matching subsequences will be yielded from - # +seq1+ in turn and may be modified before they are placed into the - # returned Array of subsequences. - def LCS(seq1, seq2, &block) #:yields seq1[ii] for each matched: - matches = Diff::LCS.__lcs(seq1, seq2) - ret = [] - matches.each_with_index do |ee, ii| - unless matches[ii].nil? - if block_given? - ret << (yield seq1[ii]) - else - ret << seq1[ii] - end - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. - # - # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. - # If a Class argument is provided for +callbacks+, #diff will attempt - # to initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes: - callbacks ||= Diff::LCS::DiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_sequences(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility <em>sdiff</em> does: - # - # old < - - # same same - # before | after - # - > new - # - # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If - # a Class argument is provided for +callbacks+, #diff will attempt to - # initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes: - callbacks ||= Diff::LCS::SDiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_balanced(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # The arguments to #traverse_sequences are the two sequences to - # traverse, and a callback object, like this: - # - # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #diff is implemented with #traverse_sequences. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#finished_a</em>:: Called when +a+ has reached the end of - # sequence +A+. - # <em>callbacks#finished_b</em>:: Called when +b+ has reached the end of - # sequence +B+. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, depending - # on which arrow it advanced. If both arrows point to elements that are - # not part of the longest common subsequence, then #traverse_sequences - # will advance one of them and call the appropriate callback, but it is - # not specified which it will call. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # and <tt>callbacks#discard_b</tt> are invoked with an event comprising - # the action ("=", "+", or "-", respectively), the indicies +ii+ and - # +jj+, and the elements <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return - # values are discarded by #traverse_sequences. - # - # === End of Sequences - # If arrow +a+ reaches the end of its sequence before arrow +b+ does, - # #traverse_sequence try to call <tt>callbacks#finished_a</tt> with the - # last index and element of +A+ (<tt>A[-1]</tt>) and the current index - # and element of +B+ (<tt>B[jj]</tt>). If <tt>callbacks#finished_a</tt> - # does not exist, then <tt>callbacks#discard_b</tt> will be called on - # each element of +B+ until the end of the sequence is reached (the call - # will be done with <tt>A[-1]</tt> and <tt>B[jj]</tt> for each element). - # - # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+, - # <tt>callbacks#finished_b</tt> will be called with the current index - # and element of +A+ (<tt>A[ii]</tt>) and the last index and element of - # +B+ (<tt>A[-1]</tt>). Again, if <tt>callbacks#finished_b</tt> does not - # exist on the callback object, then <tt>callbacks#discard_a</tt> will - # be called on each element of +A+ until the end of the sequence is - # reached (<tt>A[ii]</tt> and <tt>B[-1]</tt>). - # - # There is a chance that one additional <tt>callbacks#discard_a</tt> or - # <tt>callbacks#discard_b</tt> will be called after the end of the - # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+ - # has not yet reached the end of +B+. - def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events: - matches = Diff::LCS.__lcs(seq1, seq2) - - run_finished_a = run_finished_b = false - string = seq1.kind_of?(String) - - a_size = seq1.size - b_size = seq2.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? seq1[ii, 1] : seq1[ii] - bx = string ? seq2[bj, 1] : seq2[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::ContextChange.new('-', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? seq1[-1, 1] : seq1[-1] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx) - event = yield event if block_given? - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? seq1[ai, 1] : seq1[ai] - loop do - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[-1, 1] : seq2[-1] - event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx) - event = yield event if block_given? - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? seq2[bj, 1] : seq2[bj] - loop do - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - # #traverse_balanced is an alternative to #traverse_sequences. It - # uses a different algorithm to iterate through the entries in the - # computed longest common subsequence. Instead of viewing the changes as - # insertions or deletions from one of the sequences, #traverse_balanced - # will report <em>changes</em> between the sequences. To represent a - # - # The arguments to #traverse_balanced are the two sequences to traverse - # and a callback object, like this: - # - # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #sdiff is implemented with #traverse_balanced. - # - # == Callback Methods - # Optional callback methods are <em>emphasized</em>. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # <em>callbacks#change</em>:: Called when +a+ and +b+ are pointing - # to the same relative position, but - # <tt>A[a]</tt> and <tt>B[b]</tt> are - # not the same; a <em>change</em> has - # occurred. - # - # #traverse_balanced might be a bit slower than #traverse_sequences, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # #traverse_balanced. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # === Matches - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements <tt>A[ii]</tt> and <tt>B[jj]</tt> which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to <tt>A[ii]</tt> and arrow +b+ is pointing to <tt>B[jj]</tt>. When - # this happens, #traverse_sequences will call <tt>callbacks#match</tt> - # and then it will advance both arrows. - # - # === Discards - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # <tt>callbacks#discard_a</tt> or <tt>callbacks#discard_b</tt>, - # depending on which arrow it advanced. - # - # === Changes - # If both +a+ and +b+ point to elements that are not part of the longest - # common subsequence, then #traverse_sequences will try to call - # <tt>callbacks#change</tt> and advance both arrows. If - # <tt>callbacks#change</tt> is not implemented, then - # <tt>callbacks#discard_a</tt> and <tt>callbacks#discard_b</tt> will be - # called in turn. - # - # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, - # <tt>callbacks#discard_b</tt>, and <tt>callbacks#change</tt> are - # invoked with an event comprising the action ("=", "+", "-", or "!", - # respectively), the indicies +ii+ and +jj+, and the elements - # <tt>A[ii]</tt> and <tt>B[jj]</tt>. Return values are discarded by - # #traverse_balanced. - # - # === Context - # Note that +ii+ and +jj+ may not be the same index position, even if - # +a+ and +b+ are considered to be pointing to matching or changed - # elements. - def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(seq1, seq2) - a_size = seq1.size - b_size = seq2.size - ai = bj = mb = 0 - ma = -1 - string = seq1.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(seq2) - while (ai < ma) or (bj < mb) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - PATCH_MAP = { #:nodoc: - :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }, - :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' } - } - - # Given a patchset, convert the current version to the new - # version. If +direction+ is not specified (must be - # <tt>:patch</tt> or <tt>:unpatch</tt>), then discovery of the - # direction of the patch will be attempted. - def patch(src, patchset, direction = nil) - string = src.kind_of?(String) - # Start with a new empty type of the source's class - res = src.class.new - - # Normalize the patchset. - patchset = __normalize_patchset(patchset) - - direction ||= Diff::LCS.__diff_direction(src, patchset) - direction ||= :patch - - ai = bj = 0 - - patchset.each do |change| - # Both Change and ContextChange support #action - action = PATCH_MAP[direction][change.action] - - case change - when Diff::LCS::ContextChange - case direction - when :patch - el = change.new_element - op = change.old_position - np = change.new_position - when :unpatch - el = change.old_element - op = change.new_position - np = change.old_position - end - - case action - when '-' # Remove details from the old string - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < np - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res << el - bj += 1 - when '=' - # This only appears in sdiff output with the SDiff callback. - # Therefore, we only need to worry about dealing with a single - # element. - res << el - - ai += 1 - bj += 1 - when '!' - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - ai += 1 - - res << el - end - when Diff::LCS::Change - case action - when '-' - while ai < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - - res << change.element - end - end - end - - while ai < src.size - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res - end - - # Given a set of patchset, convert the current version to the prior - # version. Does no auto-discovery. - def unpatch!(src, patchset) - Diff::LCS.patch(src, patchset, :unpatch) - end - - # Given a set of patchset, convert the current version to the next - # version. Does no auto-discovery. - def patch!(src, patchset) - Diff::LCS.patch(src, patchset, :patch) - end - -# private - # Compute the longest common subsequence between the sequenced Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. (Currently unused.) - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Examine the patchset and the source to see in which direction the - # patch should be applied. - # - # WARNING: By default, this examines the whole patch, so this could take - # some time. This also works better with Diff::LCS::ContextChange or - # Diff::LCS::Change as its source, as an array will cause the creation - # of one of the above. - def __diff_direction(src, patchset, limit = nil) - count = left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - patchset.each do |change| - count += 1 - - case change - when Diff::LCS::Change - # With a simplistic change, we can't tell the difference between - # the left and right on '!' actions, so we ignore those. On '=' - # actions, if there's a miss, we miss both left and right. - element = string ? src[change.position, 1] : src[change.position] - - case change.action - when '-' - if element == change.element - left += 1 - else - left_miss += 1 - end - when '+' - if element == change.element - right += 1 - else - right_miss += 1 - end - when '=' - if element != change.element - left_miss += 1 - right_miss += 1 - end - end - when Diff::LCS::ContextChange - case change.action - when '-' # Remove details from the old string - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - left_miss += 1 - end - when '+' - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - right_miss += 1 - end - when '=' - le = string ? src[change.old_position, 1] : src[change.old_position] - re = string ? src[change.new_position, 1] : src[change.new_position] - - left_miss += 1 if le != change.old_element - right_miss += 1 if re != change.new_element - when '!' - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - left_miss += 1 - right_miss += 1 - end - end - end - end - - break if not limit.nil? and count > limit - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided patchset does not appear to apply to the provided value as either source or destination value." - end - end - - # Normalize the patchset. A patchset is always a sequence of changes, but - # how those changes are represented may vary, depending on how they were - # generated. In all cases we support, we also support the array - # representation of the changes. The formats are: - # - # [ # patchset <- Diff::LCS.diff(a, b) - # [ # one or more hunks - # Diff::LCS::Change # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, line, value ] # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.diff(a, b, Diff::LCS::ContextDiffCallbacks) - # # OR <- Diff::LCS.sdiff(a, b, Diff::LCS::ContextDiffCallbacks) - # [ # one or more hunks - # Diff::LCS::ContextChange # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.sdiff(a, b) - # # OR <- Diff::LCS.diff(a, b, Diff::LCS::SDiffCallbacks) - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset, equivalent to the above - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] - # - # The result of this will be either of the following. - # - # [ # patchset - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset - # Diff::LCS::Change # one or more changes - # ] - # - # If either of the above is provided, it will be returned as such. - # - def __normalize_patchset(patchset) - patchset.map do |hunk| - case hunk - when Diff::LCS::ContextChange, Diff::LCS::Change - hunk - when Array - if (not hunk[0].kind_of?(Array)) and hunk[1].kind_of?(Array) and hunk[2].kind_of?(Array) - Diff::LCS::ContextChange.from_a(hunk) - else - hunk.map do |change| - case change - when Diff::LCS::ContextChange, Diff::LCS::Change - change - when Array - # change[1] will ONLY be an array in a ContextChange#to_a call. - # In Change#to_a, it represents the line (singular). - if change[1].kind_of?(Array) - Diff::LCS::ContextChange.from_a(change) - else - Diff::LCS::Change.from_a(change) - end - end - end - end - else - raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}." - end - end.flatten - end - end -end diff --git a/diff-lcs/trunk/lib/diff/lcs/array.rb b/diff-lcs/trunk/lib/diff/lcs/array.rb deleted file mode 100644 index e07f8aa..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/array.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into the Array built-in class. - -require 'diff/lcs' - -class Array - include Diff::LCS -end diff --git a/diff-lcs/trunk/lib/diff/lcs/block.rb b/diff-lcs/trunk/lib/diff/lcs/block.rb deleted file mode 100644 index 7dceb48..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/block.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Block for bin/ldiff. - - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/ldiff. -class Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else # [true, true] - '^' - end - end -end diff --git a/diff-lcs/trunk/lib/diff/lcs/callbacks.rb b/diff-lcs/trunk/lib/diff/lcs/callbacks.rb deleted file mode 100644 index 74a1cdc..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,322 +0,0 @@ -#! /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$ -#++ -# Contains definitions for all default callback objects. - -require 'diff/lcs/change' - -module Diff::LCS - # This callback object implements the default set of callback events, which - # only returns the event itself. Note that #finished_a and #finished_b are - # not implemented -- I haven't yet figured out where they would be useful. - # - # Note that this is intended to be called as is, e.g., - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks) - class DefaultCallbacks - class << self - # Called when two items match. - def match(event) - event - end - # Called when the old value is discarded in favour of the new value. - def discard_a(event) - event - end - # Called when the new value is discarded in favour of the old value. - def discard_b(event) - event - end - # Called when both the old and new values have changed. - def change(event) - event - end - - private :new - end - end - - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_sequences. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks) - SequenceCallbacks = DefaultCallbacks - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_balanced. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks) - BalancedCallbacks = DefaultCallbacks -end - - # This will produce a compound array of simple diff change objects. Each - # element in the #diffs array is a +hunk+ or +hunk+ array, where each - # element in each +hunk+ array is a single Change object representing the - # addition or removal of a single element from one of the two tested - # sequences. The +hunk+ provides the full context for the changes. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ [ '-', 0, 'a' ] ], # 1 - # # [ [ '+', 2, 'd' ] ], # 2 - # # [ [ '-', 4, 'h' ], # 3 - # # [ '+', 4, 'f' ] ], - # # [ [ '+', 6, 'k' ] ], # 4 - # # [ [ '-', 8, 'n' ], # 5 - # # [ '-', 9, 'p' ], - # # [ '+', 9, 'r' ], - # # [ '+', 10, 's' ], - # # [ '+', 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at position 0 - # of the first sequence should be deleted (<tt>'-'</tt>). The second hunk - # says that the +d+ at position 2 of the second sequence should be inserted - # (<tt>'+'</tt>). The third hunk says that the +h+ at position 4 of the - # first sequence should be removed and replaced with the +f+ from position 4 - # of the second sequence. The other two hunks are described similarly. - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#diff - # method. - # - # cbo = Diff::LCS::DiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::DiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize # :yields self: - @hunk = [] - @diffs = [] - - if block_given? - begin - yield self - ensure - self.finish - end - end - end - - # Finalizes the diff process. If an unprocessed hunk still exists, then it - # is appended to the diff list. - def finish - add_nonempty_hunk - end - - def match(event) - add_nonempty_hunk - end - - def discard_a(event) - @hunk << Diff::LCS::Change.new('-', event.old_position, event.old_element) - end - - def discard_b(event) - @hunk << Diff::LCS::Change.new('+', event.new_position, event.new_element) - end - -private - def add_nonempty_hunk - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end -end - - # This will produce a compound array of contextual diff change objects. Each - # element in the #diffs array is a "hunk" array, where each element in each - # "hunk" array is a single change. Each change is a Diff::LCS::ContextChange - # that contains both the old index and new index values for the change. The - # "hunk" provides the full context for the changes. Both old and new objects - # will be presented for changed objects. +nil+ will be substituted for a - # discarded object. - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks) - # # This example shows a simplified array format. - # # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1 - # # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2 - # # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3 - # # [ '+', [ 5, nil ], [ 4, 'f' ] ] ], - # # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4 - # # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5 - # # [ '+', [ 9, nil ], [ 9, 'r' ] ], - # # [ '-', [ 9, 'p' ], [ 10, nil ] ], - # # [ '+', [ 10, nil ], [ 10, 's' ] ], - # # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ] - # - # The five hunks shown are comprised of individual changes; if there is a - # related set of changes, they are still shown individually. - # - # This callback can also be used with Diff::LCS#sdiff, which will produce - # results like: - # - # diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks) - # # This example shows a simplified array format. - # # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1 - # # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2 - # # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3 - # # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4 - # # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5 - # # [ "!", [ 9, "p" ], [ 10, "s" ] ], - # # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ] - # - # The five hunks are still present, but are significantly shorter in total - # presentation, because changed items are shown as changes ("!") instead of - # potentially "mismatched" pairs of additions and deletions. - # - # The result of this operation is similar to that of - # Diff::LCS::SDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and can be used by the - # Diff::LCS#diff or Diff::LCS#sdiff methods. - # - # cbo = Diff::LCS::ContextDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class Diff::LCS::ContextDiffCallbacks < Diff::LCS::DiffCallbacks - def discard_a(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end -end - - # This will produce a simple array of diff change objects. Each element in - # the #diffs array is a single ContextChange. In the set of #diffs provided - # by SDiffCallbacks, both old and new objects will be presented for both - # changed <strong>and unchanged</strong> objects. +nil+ will be substituted - # for a discarded object. - # - # The diffset produced by this callback, when provided to Diff::LCS#sdiff, - # will compute and display the necessary components to show two sequences - # and their minimized differences side by side, just like the Unix utility - # +sdiff+. - # - # same same - # before | after - # old < - - # - > new - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.sdiff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ "-", [ 0, "a"], [ 0, nil ] ], - # # [ "=", [ 1, "b"], [ 0, "b" ] ], - # # [ "=", [ 2, "c"], [ 1, "c" ] ], - # # [ "+", [ 3, nil], [ 2, "d" ] ], - # # [ "=", [ 3, "e"], [ 3, "e" ] ], - # # [ "!", [ 4, "h"], [ 4, "f" ] ], - # # [ "=", [ 5, "j"], [ 5, "j" ] ], - # # [ "+", [ 6, nil], [ 6, "k" ] ], - # # [ "=", [ 6, "l"], [ 7, "l" ] ], - # # [ "=", [ 7, "m"], [ 8, "m" ] ], - # # [ "!", [ 8, "n"], [ 9, "r" ] ], - # # [ "!", [ 9, "p"], [ 10, "s" ] ], - # # [ "+", [ 10, nil], [ 11, "t" ] ] ] - # - # The result of this operation is similar to that of - # Diff::LCS::ContextDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#sdiff - # method. - # - # cbo = Diff::LCS::SDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # - # As with the other initialisable callback objects, Diff::LCS::SDiffCallbacks - # can be initialised with a block. As there is no "fininishing" to be done, - # this has no effect on the state of the object. - # - # cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.to_a } -class Diff::LCS::SDiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize #:yields self: - @diffs = [] - yield self if block_given? - end - - def match(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_a(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end -end diff --git a/diff-lcs/trunk/lib/diff/lcs/change.rb b/diff-lcs/trunk/lib/diff/lcs/change.rb deleted file mode 100644 index 6ecdf7e..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/change.rb +++ /dev/null @@ -1,169 +0,0 @@ -#! /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$ -#++ -# 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 diff --git a/diff-lcs/trunk/lib/diff/lcs/hunk.rb b/diff-lcs/trunk/lib/diff/lcs/hunk.rb deleted file mode 100644 index 58fac9f..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,257 +0,0 @@ -#! /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$ -#++ -# Contains Diff::LCS::Hunk for bin/ldiff. - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/diff-lcs/trunk/lib/diff/lcs/ldiff.rb b/diff-lcs/trunk/lib/diff/lcs/ldiff.rb deleted file mode 100644 index 61abc47..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/ldiff.rb +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require 'ostruct' -require 'diff/lcs/hunk' - - # == ldiff Usage - # ldiff [options] oldfile newfile - # - # -c:: Displays a context diff with 3 lines of context. - # -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. - # -u:: Displays a unified diff with 3 lines of context. - # -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. - # -e:: Creates an 'ed' script to change oldfile to newfile. - # -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. - # -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. - # --binary:: Treats the files as binary. - # -q, --brief:: Reports only whether or not the files differ, not the details. - # --help:: Shows the command-line help. - # --version:: Shows the version of Diff::LCS. - # - # By default, runs produces an "old-style" diff, with output like UNIX diff. - # - # == Copyright - # Copyright © 2004 Austin Ziegler - # - # Part of Diff::LCS <http://rubyforge.org/projects/ruwiki/> - # Austin Ziegler <diff-lcs@halostatue.ca> - # - # 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. -module Diff::LCS::Ldiff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler <diff-lcs@halostatue.ca> - - 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$ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def run(args, input = $stdin, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end diff --git a/diff-lcs/trunk/lib/diff/lcs/string.rb b/diff-lcs/trunk/lib/diff/lcs/string.rb deleted file mode 100644 index 2de7d1f..0000000 --- a/diff-lcs/trunk/lib/diff/lcs/string.rb +++ /dev/null @@ -1,19 +0,0 @@ -#! /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$ -#++ -# Includes Diff::LCS into String. - -class String - include Diff::LCS -end diff --git a/diff-lcs/trunk/tests/00test.rb b/diff-lcs/trunk/tests/00test.rb deleted file mode 100644 index 8872dfd..0000000 --- a/diff-lcs/trunk/tests/00test.rb +++ /dev/null @@ -1,626 +0,0 @@ -#! /usr/bin/env ruby -# -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::ContextChange) - diffs.map do |chunks| - if klass == Diff::LCS::ContextChange - klass.from_a(chunks) - else - chunks.map { |changes| klass.from_a(changes) } - end - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_element - @matched_b << event.new_element - end - - def discard_b(event) - @discards_b << event.new_element - end - - def discard_a(event) - @discards_a << event.old_element - end - - def finished_a(event) - @done_a << [event.old_element, event.old_position] - end - - def finished_b(event) - @done_b << [event.new_element, event.new_position] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_position}#{event.new_position} " - end - - def discard_a(event) - @result << "DA#{event.old_position}#{event.new_position} " - end - - def discard_b(event) - @result << "DB#{event.old_position}#{event.new_position} " - end - - def change(event) - @result << "C#{event.old_position}#{event.new_position} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ '=', [ 0, 'abc' ], [ 0, 'abc' ] ], - [ '!', [ 1, 'def' ], [ 1, 'dxf' ] ], - [ '-', [ 2, 'yyy' ], [ 2, nil ] ], - [ '=', [ 3, 'xxx' ], [ 2, 'xxx' ] ], - [ '=', [ 4, 'ghi' ], [ 3, 'ghi' ] ], - [ '=', [ 5, 'jkl' ], [ 4, 'jkl' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '=', [ 1, 'b' ], [ 0, 'b' ] ], - [ '=', [ 2, 'c' ], [ 1, 'c' ] ], - [ '+', [ 3, nil ], [ 2, 'd' ] ], - [ '=', [ 3, 'e' ], [ 3, 'e' ] ], - [ '!', [ 4, 'h' ], [ 4, 'f' ] ], - [ '=', [ 5, 'j' ], [ 5, 'j' ] ], - [ '+', [ 6, nil ], [ 6, 'k' ] ], - [ '=', [ 6, 'l' ], [ 7, 'l' ] ], - [ '=', [ 7, 'm' ], [ 8, 'm' ] ], - [ '!', [ 8, 'n' ], [ 9, 'r' ] ], - [ '!', [ 9, 'p' ], [ 10, 's' ] ], - [ '+', [ 10, nil ], [ 11, 't' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ], - [ '-', [ 3, 'd' ], [ 1, nil ] ], - [ '=', [ 4, 'e' ], [ 1, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '+', [ 1, nil ], [ 1, 'b' ] ], - [ '+', [ 1, nil ], [ 2, 'c' ] ], - [ '+', [ 1, nil ], [ 3, 'd' ] ], - [ '=', [ 1, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', [ 0, 'v' ], [ 0, 'w' ] ], - [ '!', [ 1, 'x' ], [ 1, 'y' ] ], - [ '=', [ 2, 'a' ], [ 2, 'a' ] ], - [ '+', [ 3, nil ], [ 3, 'b' ] ], - [ '+', [ 3, nil ], [ 4, 'c' ] ], - [ '+', [ 3, nil ], [ 5, 'd' ] ], - [ '=', [ 3, 'e' ], [ 6, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', [ 0, 'x' ], [ 0, nil ] ], - [ '=', [ 1, 'a' ], [ 0, 'a' ] ], - [ '+', [ 2, nil ], [ 1, 'b' ] ], - [ '+', [ 2, nil ], [ 2, 'c' ] ], - [ '+', [ 2, nil ], [ 3, 'd' ] ], - [ '=', [ 2, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ], - [ '!', [ 2, 'v' ], [ 6, 'w' ] ], - [ '+', [ 3, nil ], [ 7, 'x' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'a' ] ], - [ '+', [ 0, nil ], [ 1, 'b' ] ], - [ '+', [ 0, nil ], [ 2, 'c' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '-', [ 2, 'c' ], [ 0, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', [ 0, 'a' ], [ 0, '1' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '=', [ 2, 'c' ], [ 0, 'c' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', [ 0, 'abcd' ], [ 0, nil ] ], - [ '-', [ 1, 'efgh' ], [ 0, nil ] ], - [ '-', [ 2, 'ijkl' ], [ 0, nil ] ], - [ '-', [ 3, 'mnop' ], [ 0, nil ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'abcd' ] ], - [ '+', [ 0, nil ], [ 1, 'efgh' ] ], - [ '+', [ 0, nil ], [ 2, 'ijkl' ] ], - [ '+', [ 0, nil ], [ 3, 'mnop' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end - -class TestPatching < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_patch_diff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms2 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::SDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end - - # Tests patch bug #891: - # http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 - def test_patch_bug891 - s1 = s2 = s3 = s4 = s5 = ps = nil - assert_nothing_raised do - s1 = %w{a b c d e f g h i j k } - s2 = %w{a b c d D e f g h i j k } - ps = Diff::LCS::diff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::SDiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - - assert_nothing_raised do - ps = Diff::LCS::sdiff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::DiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - end - - def test_patch_sdiff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::DiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end -end diff --git a/diff-lcs/tags/release-1.1.1/install.rb b/install.rb index 4bd3d7a..4bd3d7a 100644 --- a/diff-lcs/tags/release-1.1.1/install.rb +++ b/install.rb diff --git a/diff-lcs/tags/release-1.1.2/lib/diff/lcs.rb b/lib/diff/lcs.rb index b74b2d3..b74b2d3 100644 --- a/diff-lcs/tags/release-1.1.2/lib/diff/lcs.rb +++ b/lib/diff/lcs.rb diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/array.rb b/lib/diff/lcs/array.rb index e07f8aa..e07f8aa 100644 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/array.rb +++ b/lib/diff/lcs/array.rb diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/block.rb b/lib/diff/lcs/block.rb index 7dceb48..7dceb48 100644 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/block.rb +++ b/lib/diff/lcs/block.rb diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/callbacks.rb b/lib/diff/lcs/callbacks.rb index 74a1cdc..74a1cdc 100644 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/callbacks.rb +++ b/lib/diff/lcs/callbacks.rb diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/change.rb b/lib/diff/lcs/change.rb index 6ecdf7e..6ecdf7e 100644 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/change.rb +++ b/lib/diff/lcs/change.rb diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/hunk.rb b/lib/diff/lcs/hunk.rb index 58fac9f..58fac9f 100644 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/hunk.rb +++ b/lib/diff/lcs/hunk.rb diff --git a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/ldiff.rb b/lib/diff/lcs/ldiff.rb index 61abc47..61abc47 100644 --- a/diff-lcs/tags/release-1.1.1/lib/diff/lcs/ldiff.rb +++ b/lib/diff/lcs/ldiff.rb diff --git a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/string.rb b/lib/diff/lcs/string.rb index 2de7d1f..2de7d1f 100644 --- a/diff-lcs/tags/release-1.1.0/lib/diff/lcs/string.rb +++ b/lib/diff/lcs/string.rb diff --git a/diff-lcs/tags/release-1.1.1/tests/00test.rb b/tests/00test.rb index 8872dfd..8872dfd 100644 --- a/diff-lcs/tags/release-1.1.1/tests/00test.rb +++ b/tests/00test.rb |