-
Notifications
You must be signed in to change notification settings - Fork 48
/
differ.rb
83 lines (68 loc) · 1.84 KB
/
differ.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
require 'differ/change'
require 'differ/diff'
require 'differ/format/ascii'
require 'differ/format/color'
require 'differ/format/html'
module Differ
class << self
def diff(target, source, separator = "\n")
old_sep, $; = $;, separator
target = target.split(separator)
source = source.split(separator)
$; = '' if separator.is_a? Regexp
@diff = Diff.new
advance(target, source) until source.empty? || target.empty?
@diff.insert(*target) || @diff.delete(*source)
return @diff
ensure
$; = 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
return @format || Format::Ascii
end
def format_for(f)
case f
when Module then f
when :ascii then Format::Ascii
when :color then Format::Color
when :html then Format::HTML
when nil then nil
else raise "Unknown format type #{f.inspect}"
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