diff options
author | Austin Ziegler <austin@halostatue.ca> | 2011-07-31 11:28:19 -0400 |
---|---|---|
committer | Austin Ziegler <austin@halostatue.ca> | 2011-07-31 11:28:19 -0400 |
commit | 8b51589f8e3bc2e98bfdf5d0038a30698a331f2e (patch) | |
tree | 6d13c4a4e7f80eff5a647e1c40d4720c86c7fd90 | |
parent | 2276593be732e5c91cac144d1fad0310e072613b (diff) | |
download | diff-lcs-8b51589f8e3bc2e98bfdf5d0038a30698a331f2e.tar.gz |
Fixing https://github.com/halostatue/diff-lcs/issues/4
-rw-r--r-- | History.rdoc | 5 | ||||
-rw-r--r-- | bin/htmldiff | 120 | ||||
-rw-r--r-- | bin/ldiff | 41 | ||||
-rw-r--r-- | lib/diff/lcs/htmldiff.rb | 151 |
4 files changed, 177 insertions, 140 deletions
diff --git a/History.rdoc b/History.rdoc index feebcf0..0943f0f 100644 --- a/History.rdoc +++ b/History.rdoc @@ -1,5 +1,10 @@ == 1.1.3 / 2011-07-30 +* Converted to 'hoe' for release. +* Converted tests to RSpec 2. * Bugs fixed: + - Issue 4 (https://github.com/halostatue/diff-lcs/issues/4) fixed. + In the process, HTMLDiff was made easier to use outside of the htmldiff + command. == 1.1.2 / 2004-10-20 * Fixed a problem reported by Mauricio Fernandez in htmldiff. Future versions diff --git a/bin/htmldiff b/bin/htmldiff index 509860c..056564c 100644 --- a/bin/htmldiff +++ b/bin/htmldiff @@ -1,112 +1,32 @@ #!/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/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 @@ -1,45 +1,6 @@ #!/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' require 'diff/lcs/ldiff' exit Diff::LCS::Ldiff.run(ARGV) diff --git a/lib/diff/lcs/htmldiff.rb b/lib/diff/lcs/htmldiff.rb new file mode 100644 index 0000000..bf576a2 --- /dev/null +++ b/lib/diff/lcs/htmldiff.rb @@ -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 |