Class: Websitary::Htmldiff

Inherits:
Object
  • Object
show all
Defined in:
lib/websitary/htmldiff.rb

Overview

A simple class to generate diffs for html files using hpricot. It’s quite likely that it will miss certain details and yields wrong results (especially wrong-negative) in certain occasions.

Constant Summary collapse

VERSION =
'0.1'
REVISION =
'164'

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ Htmldiff

args

A hash

Fields:

:oldtext

The old version

:newtext

The new version

:highlight

Don’t strip old content but highlight new one with this color

:args

Command-line arguments



28
29
30
31
32
33
34
# File 'lib/websitary/htmldiff.rb', line 28

def initialize(args)
    @args = args
    @high = args[:highlight] || args[:highlightcolor]
    @old  = explode(args[:olddoc] || Hpricot(args[:oldtext] || File.read(args[:oldfile])))
    @new  =         args[:newdoc] || Hpricot(args[:newtext] || File.read(args[:newfile]))
    @changed = false
end

Instance Method Details

#diffObject

Do the diff. Return an empty string if nothing has changed.



38
39
40
41
# File 'lib/websitary/htmldiff.rb', line 38

def diff
    rv = process.to_s
    @changed ? rv : ''
end

#explode(node) ⇒ Object

Collect all nodes and subnodes in a hpricot document.



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/websitary/htmldiff.rb', line 71

def explode(node)
    if node.respond_to?(:each_child)
        acc = [node.to_html.strip]
        node.each_child do |child|
            acc += explode(child)
        end
        acc
    else
        [node.to_html.strip]
    end
end

#highlight(child) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/websitary/htmldiff.rb', line 84

def highlight(child)
    @changed = true
    if @high
        if child.respond_to?(:each_child)
            acc = []
            child.each_child do |ch|
                acc << replace_inner(ch, highlight(ch).to_s)
            end
            replace_inner(child, acc.join("\n"))
        else
            case @args[:highlight]
            when String
                opts = %{class="#{@args[:highlight]}"}
            when true, Numeric
                opts = %{class="highlight"}
            else
                opts = %{style="background-color: #{@args[:highlightcolor]};"}
            end
            ihtml = %{<span #{opts}>#{child.to_s}</span>}
            replace_inner(child, ihtml)
        end
    else
        child
    end
end

#process(node = @new) ⇒ Object

It goes like this: if a node isn’t in the list of old nodes either the node or its content has changed. If the content is a single node, the whole node has changed. If only some sub-nodes have changed, collect those.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/websitary/htmldiff.rb', line 48

def process(node=@new)
    acc    = []
    node.each_child do |child|
        ch = child.to_html.strip
        next if ch.nil? or ch.empty?
        if @old.include?(ch)
            if @high
                acc << child
            end
        else
            if child.respond_to?(:each_child)
                acc << process(child)
            else
                acc << highlight(child).to_s
                acc << '<br />' unless @high
            end
        end
    end
    replace_inner(node, acc.join("\n"))
end

#replace_inner(child, ihtml) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/websitary/htmldiff.rb', line 111

def replace_inner(child, ihtml)
    case child
    when Hpricot::Comment
        child
    when Hpricot::Text
        Hpricot(ihtml)
    else
        child.inner_html = ihtml
        child
    end
end