Module: Rsxml::Sexp

Defined in:
lib/rsxml/sexp.rb

Defined Under Namespace

Classes: ComparisonError

Class Method Summary collapse

Class Method Details

.compare(sexpa, sexpb, path = nil) ⇒ Object

Raises:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rsxml/sexp.rb', line 70

def compare(sexpa, sexpb, path=nil)
  taga, attrsa, childrena = decompose_sexp(sexpa)
  tagb, attrsb, childrenb = decompose_sexp(sexpb)

  raise ComparisonError.new("element names differ: '#{taga}', '#{tagb}'", path) if taga != tagb
  raise ComparisonError.new("attributes differ", path) if attrsa != attrsb
  raise ComparisonError.new("child count differs", path) if childrena.length != childrenb.length

  path = [path, taga].compact.join("/")
  (0...childrena.length).each do |i|
    if childrena[i].is_a?(Array) && childrenb[i].is_a?(Array)
      compare(childrena[i], childrenb[i], path)
    else
      raise ComparisonError.new("content differs: '#{childrena[i]}', '#{childrenb[i]}'", path) if childrena[i] != childrenb[i]
    end
  end
  true
end

.decompose_sexp(sexp) ⇒ Object

decompose a sexp to a [tag, attrs, children] list



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/rsxml/sexp.rb', line 45

def decompose_sexp(sexp)
  raise "invalid rsxml: #{rsxml.inspect}" if sexp.length<1
  if sexp[0].is_a?(Array)
    tag = sexp[0]
  else
    tag = sexp[0].to_s
  end
  if sexp[1].is_a?(Hash)
    attrs = sexp[1]
    children = sexp[2..-1]
  else
    attrs = {}
    children = sexp[1..-1]
  end
  [tag, attrs, children]
end

.traverse(sexp, visitor, context = Visitor::Context.new) ⇒ Object

pre-order traversal of the sexp, calling methods on the visitor with each node



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
# File 'lib/rsxml/sexp.rb', line 8

def traverse(sexp, visitor, context=Visitor::Context.new)
  tag, attrs, children = decompose_sexp(sexp)
  
  ns_bindings, ns_additional_decls = Namespace::namespace_bindings_declarations(context.ns_stack, tag, attrs)

  context.ns_stack.push(ns_bindings)

  etag = Namespace::explode_qname(context.ns_stack, tag)
  eattrs = Namespace::explode_attr_qnames(context.ns_stack, attrs)

  eattrs = eattrs.merge(ns_additional_decls)

  begin
    visitor.tag(context, etag, eattrs) do
      context.push_node([etag, eattrs])
      begin
        children.each_with_index do |child, i|
          if child.is_a?(Array)
            traverse(child, visitor, context)
          else
            visitor.text(context, child)
            context.processed_node(child)
          end
        end
      ensure
        context.pop_node
      end
    end

  ensure
    context.ns_stack.pop
  end

  visitor
end