lib/differ.rb
require 'differ/change'
require 'differ/diff'
require 'differ/format/ascii'
require 'differ/format/color'
require 'differ/format/html'
module Differ
class << self
@@separator = ''
def separator=(separator)
@@separator = separator
end
def separator
@@separator
end
def diff(target, source, new_sep = "\n")
old_sep = separator
self.separator = new_sep
target = target.split(new_sep)
source = source.split(new_sep)
self.separator = '' if new_sep.is_a? Regexp
@diff = Diff.new
advance(target, source) until source.empty? || target.empty?
@diff.insert(*target) || @diff.delete(*source)
return @diff
ensure
self.separator = old_sep
end
def diff_by_char(to, from)
diff(to, from, '')
end
def diff_by_word(to, from)
diff(to, from, /\b/)
end
def diff_by_line(to, from)
diff(to, from, "\n")
end
def format=(f)
@format = format_for(f)
end
def format
@format || Format::Ascii
end
def format_for(f)
if f.respond_to? :call
f
else
case f
when :ascii then Format::Ascii
when :color then Format::Color
when :html then Format::HTML
when nil then nil
else fail "Unknown format type #{f.inspect}"
end
end
end
private
def advance(target, source)
del, add = source.shift, target.shift
prioritize_insert = target.length > source.length
insert = target.index(del)
delete = source.index(add)
if del == add
@diff.same(add)
elsif insert && prioritize_insert
change(:insert, target.unshift(add), insert)
elsif delete
change(:delete, source.unshift(del), delete)
elsif insert && !prioritize_insert
change(:insert, target.unshift(add), insert)
else
@diff.insert(add) && @diff.delete(del)
end
end
def change(method, array, index)
@diff.send(method, *array.slice!(0..index))
@diff.same(array.shift)
end
end
end