-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Austin Ziegler
committed
Jul 31, 2011
1 parent
2276593
commit 8b51589
Showing
4 changed files
with
177 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,32 @@ | ||
#!/usr/bin/env ruby | ||
#-- | ||
# Copyright 2004 Austin Ziegler <[email protected]> | ||
# adapted from: | ||
# Algorithm::Diff (Perl) by Ned Konz <[email protected]> | ||
# Smalltalk by Mario I. Wolczko <[email protected]> | ||
# 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' | ||
require 'diff/lcs/htmldiff' | ||
|
||
begin | ||
require 'rubygems' | ||
require_gem 'diff-lcs', "1.1.1" | ||
require 'diff/lcs/string' | ||
require 'text/format' | ||
rescue LoadError | ||
require 'diff/lcs' | ||
require 'diff/lcs/string' | ||
Diff::LCS::HTMLDiff.can_expand_tabs = false | ||
end | ||
|
||
require 'text/format' | ||
if ARGV.size < 2 or ARGV.size > 3 | ||
$stderr.puts "usage: #{File.basename($0)} old new [output.html]" | ||
$stderr.puts " #{File.basename($0)} old new > output.html" | ||
exit 127 | ||
end | ||
|
||
class HTMLDiff #:nodoc: | ||
attr_accessor :output | ||
left = IO.read(ARGV[0]).split($/) | ||
right = IO.read(ARGV[1]).split($/) | ||
|
||
def initialize(output) | ||
@output = output | ||
end | ||
options = { :title => "diff #{ARGV[0]} #{ARGV[1]}" } | ||
|
||
# This will be called with both lines are the same | ||
def match(event) | ||
@output << %Q|<pre class="match">#{event.old_element}</pre>\n| | ||
end | ||
htmldiff = Diff::LCS::HTMLDiff.new(left, right, options) | ||
|
||
# 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| | ||
if ARGV[2] | ||
File.open(ARGV[2], "w") do |f| | ||
htmldiff.options[:output] = f | ||
htmldiff.run | ||
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 | ||
else | ||
htmldiff.run | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,6 @@ | ||
#!/usr/bin/env ruby | ||
#-- | ||
# Copyright 2004 Austin Ziegler <[email protected]> | ||
# adapted from: | ||
# Algorithm::Diff (Perl) by Ned Konz <[email protected]> | ||
# Smalltalk by Mario I. Wolczko <[email protected]> | ||
# 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' | ||
require 'diff/lcs/ldiff' | ||
|
||
exit Diff::LCS::Ldiff.run(ARGV) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# -*- ruby encoding: utf-8 -*- | ||
|
||
require 'cgi' | ||
|
||
class Diff::LCS::HTMLDiff | ||
class << self | ||
attr_accessor :can_expand_tabs #:nodoc: | ||
end | ||
self.can_expand_tabs = true | ||
|
||
class Callbacks | ||
attr_accessor :output | ||
attr_accessor :match_class | ||
attr_accessor :only_a_class | ||
attr_accessor :only_b_class | ||
|
||
def initialize(output, options = {}) | ||
@output = output | ||
options ||= {} | ||
|
||
@match_class = options[:match_class] || "match" | ||
@only_a_class = options[:only_a_class] || "only_a" | ||
@only_b_class = options[:only_b_class] || "only_b" | ||
end | ||
|
||
def htmlize(element, css_class) | ||
element = " " if element.empty? | ||
%Q|<pre class="#{__send__(css_class)}">#{element}</pre>\n| | ||
end | ||
private :htmlize | ||
|
||
# This will be called with both lines are the same | ||
def match(event) | ||
@output << htmlize(event.old_element, :match_class) | ||
end | ||
|
||
# This will be called when there is a line in A that isn't in B | ||
def discard_a(event) | ||
@output << htmlize(event.old_element, :only_a_class) | ||
end | ||
|
||
# This will be called when there is a line in B that isn't in A | ||
def discard_b(event) | ||
@output << htmlize(event.new_element, :only_b_class) | ||
end | ||
end | ||
|
||
DEFAULT_OPTIONS = { | ||
:expand_tabs => nil, | ||
:output => nil, | ||
:css => nil, | ||
:title => nil, | ||
} | ||
|
||
DEFAULT_CSS = <<-CSS | ||
body { margin: 0; } | ||
.diff | ||
{ | ||
border: 1px solid black; | ||
margin: 1em 2em; | ||
} | ||
p | ||
{ | ||
margin-left: 2em; | ||
} | ||
pre | ||
{ | ||
padding-left: 1em; | ||
margin: 0; | ||
font-family: Inconsolata, Consolas, 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; } | ||
CSS | ||
|
||
def initialize(left, right, options = nil) | ||
@left = left | ||
@right = right | ||
@options = options | ||
|
||
@options = DEFAULT_OPTIONS.dup if @options.nil? | ||
end | ||
|
||
def verify_options | ||
@options[:expand_tabs] ||= 4 | ||
@options[:expand_tabs] = 4 if @options[:expand_tabs] < 0 | ||
|
||
@options[:output] ||= $stdout | ||
|
||
@options[:css] ||= DEFAULT_CSS.dup | ||
|
||
@options[:title] ||= "diff" | ||
end | ||
private :verify_options | ||
|
||
attr_reader :options | ||
|
||
def run | ||
verify_options | ||
|
||
if @options[:expand_tabs] > 0 && self.class.can_expand_tabs | ||
formatter = Text::Format.new | ||
formatter.tabstop = @options[:expand_tabs] | ||
|
||
@left = left.map { |line| formatter.expand(line.chomp) } | ||
@right = right.map { |line| formatter.expand(line.chomp) } | ||
end | ||
|
||
@left.map! { |line| CGI.escapeHTML(line.chomp) } | ||
@right.map! { |line| CGI.escapeHTML(line.chomp) } | ||
|
||
@options[:output] << <<-OUTPUT | ||
<html> | ||
<head> | ||
<title>#{@options[:title]}</title> | ||
<style type="text/css"> | ||
#{@options[:css]} | ||
</style> | ||
</head> | ||
<body> | ||
<h1>#{@options[:title]}</h1> | ||
<p>Legend: <span class="only_a">Only in Old</span> | ||
<span class="only_b">Only in New</span></p> | ||
<div class="diff"> | ||
OUTPUT | ||
|
||
callbacks = Callbacks.new(@options[:output]) | ||
Diff::LCS.traverse_sequences(@left, @right, callbacks) | ||
|
||
@options[:output] << <<-OUTPUT | ||
</div> | ||
</body> | ||
</html> | ||
OUTPUT | ||
end | ||
end | ||
|
||
# vim: ft=ruby |