Class: ANSI::Diff

Inherits:
Object
  • Object
show all
Defined in:
lib/ansi/diff.rb

Overview

Diff can produced a colorized difference of two string or objects.

Constant Summary collapse

COLORS =

Rotation of colors for diff output.

[:red, :yellow, :magenta]

Instance Method Summary collapse

Constructor Details

#initialize(object1, object2, options = {}) ⇒ Diff

Returns a new instance of Diff.



9
10
11
12
13
14
# File 'lib/ansi/diff.rb', line 9

def initialize(object1, object2, options={})
  @object1 = convert(object1)
  @object2 = convert(object2)

  @diff1, @diff2 = diff_string(@object1, @object2)
end

Instance Method Details

#common(x, y) ⇒ Object (private)



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ansi/diff.rb', line 74

def common(x,y)
  c = lcs(x, y)

  i = x.index(c)
  j = y.index(c)

  ix = i + c.size
  jx = j + c.size

  if i == 0 
    l = y[0...j]
  elsif j == 0
    l = x[0...i]
  else
    l = common(x[0...i], y[0...j])
  end

  if ix == x.size - 1
    r = y[jx..-1]
  elsif jx = y.size - 1
    r = x[ix..-1]
  else
    r = common(x[ix..-1], y[jx..-1])
  end

  [l, c, r].flatten.reject{ |s| s.empty? }
end

#compare(x, y) ⇒ Object (private)



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ansi/diff.rb', line 56

def compare(x, y)
  c = common(x, y)
  a = x.dup
  b = y.dup
  oi = 0
  oj = 0
  c.each_with_index do |m, q|
    i = a.index(m, oi)
    j = b.index(m, oj)
    a[i,m.size] = ANSI.ansi(m, COLORS[q%3]) if i
    b[j,m.size] = ANSI.ansi(m, COLORS[q%3]) if j
    oi = i + m.size if i
    oj = j + m.size if j
  end
  return a, b
end

#convert(object) ⇒ Object (private)

Ensure the object of comparison is a string. If object is not an instance of String then it wll be converted to one by calling either #to_str, if the object responds to it, or #inspect.



42
43
44
45
46
47
48
49
50
# File 'lib/ansi/diff.rb', line 42

def convert(object)
  if String === object
    object
  elsif object.respond_to?(:to_str)
    object.to_str
  else
    object.inspect
  end
end

#diff1Object



17
18
19
# File 'lib/ansi/diff.rb', line 17

def diff1
  @diff1
end

#diff2Object



22
23
24
# File 'lib/ansi/diff.rb', line 22

def diff2
  @diff2
end

#diff_string(string1, string2) ⇒ Object (private)

Take two plain strings and produce colorized versions of each highlighting their differences.



35
36
37
# File 'lib/ansi/diff.rb', line 35

def diff_string(string1, string2)
  compare(string1, string2)
end

#lcs(s1, s2) ⇒ Object (private)



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/ansi/diff.rb', line 120

def lcs(s1, s2)
  res="" 
  num=Array.new(s1.size){Array.new(s2.size)}
  len,ans=0
  lastsub=0
  s1.scan(/./).each_with_index do |l1,i |
    s2.scan(/./).each_with_index do |l2,j |
      unless l1==l2
        num[i][j]=0
      else
        (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
        if num[i][j] > len
          len = ans = num[i][j]
          thissub = i
          thissub -= num[i-1][j-1] unless num[i-1][j-1].nil?  
          if lastsub==thissub
            res+=s1[i,1]
          else
            lastsub=thissub
            res=s1[lastsub, (i+1)-lastsub]
          end
        end
      end
    end
  end
  res
end

#lcs_size(s1, s2) ⇒ Object (private)



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/ansi/diff.rb', line 103

def lcs_size(s1, s2)
  num=Array.new(s1.size){Array.new(s2.size)}
  len,ans=0
  s1.scan(/./).each_with_index do |l1,i |
    s2.scan(/./).each_with_index do |l2,j |
      unless l1==l2
        num[i][j]=0
      else
        (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
        len = ans = num[i][j] if num[i][j] > len
      end
    end
  end
  ans
end

#to_sObject



27
28
29
# File 'lib/ansi/diff.rb', line 27

def to_s
  "#{@diff1}\n#{@diff2}"
end