Class: RoxmlBuilder

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/roundtrip_xml/roxml_builder.rb

Overview

Classes that already exist in the DslRuntime instance are modified if necessary, not overridden.

Constant Summary

Constants included from Utils

Utils::UNDEFINED_PARAM, Utils::VAR_SUFIX

Instance Method Summary collapse

Methods included from Utils

included, #name_to_sym, #new_roxml_class

Constructor Details

#initialize(root, current_classes = {}) ⇒ RoxmlBuilder

Returns a new instance of RoxmlBuilder.



8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/roundtrip_xml/roxml_builder.rb', line 8

def initialize (root, current_classes = {})
  # @type Nokogiri::Element
  @root = root

  # @type Map<Symbol, ROXML>
  @generated_classes = current_classes

  @root_class = @generated_classes[name_to_sym(root.name)] || new_roxml_class(@root.name)

  @generated_classes[ name_to_sym(@root.name)] = @root_class
  @nodes = {}
end

Instance Method Details

#add_accessor(name, opts = {}, node) ⇒ Object



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

def add_accessor(name, opts = {}, node)
  attrs = @root_class.roxml_attrs
  attr = attrs.find do |a|
    a.accessor.to_sym == name
  end
  # if class already has xml attribute, delete the old version and add the new version

  if attr
    if node_has_child?(node, attr.accessor.to_sym)
      @root_class.instance_variable_set(:@roxml_attrs, attrs.select {|i| i != attr })
      new_attr_type = opts[:as]
      # add a new attribute with the array type.
      @root_class.xml_accessor name, opts.merge({as: [new_attr_type]})
    else
      add_child_to_node(node, name)
    end
  else
    @root_class.xml_accessor name, opts
    add_child_to_node(node, name)
  end
end

#add_child_to_node(node, child) ⇒ Object



79
80
81
82
# File 'lib/roundtrip_xml/roxml_builder.rb', line 79

def add_child_to_node(node, child)
  @nodes[node.path] ||= {}
  @nodes[node.path][child] = true
end

#build_classesObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/roundtrip_xml/roxml_builder.rb', line 23

def build_classes
  @root.attributes.values.to_a.concat(@root.children.to_a).each do |child|
    default_opts = {from:child.name}
    if is_leaf_element?(child)
      add_accessor name_to_sym(child.name, true), default_opts, @root
    elsif child.type == Nokogiri::XML::Node::ATTRIBUTE_NODE
      add_accessor name_to_sym(child.name, true), {from: "@#{child.name}"}, @root
    elsif child.type == Nokogiri::XML::Node::ELEMENT_NODE
      # making sure that child is an element here ensures text nodes don't get processed here
      builder = RoxmlBuilder.new child, @generated_classes
      new_classes = builder.build_classes
      child_name = name_to_sym(child.name, true)
      child_class_name = name_to_sym child.name
      add_accessor child_name, default_opts.merge({as: new_classes[child_class_name]}), @root
      @generated_classes.merge!(new_classes)
    elsif child.type == Nokogiri::XML::Node::TEXT_NODE && child.to_s.strip != ''
      add_accessor name_to_sym(@root.name, true), {from: :content}, @root
    end
  end

  @generated_classes
end

#is_leaf_element?(element) ⇒ Boolean

element is a leaf it has text content and no attributes

Returns:

  • (Boolean)


69
70
71
72
73
# File 'lib/roundtrip_xml/roxml_builder.rb', line 69

def is_leaf_element?(element)
  element.type == Nokogiri::XML::Node::ELEMENT_NODE &&
    element.attributes.size == 0 &&
    element.children.select {|c| c.type == Nokogiri::XML::Node::ELEMENT_NODE}.empty?
end

#node_has_child?(node, child) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/roundtrip_xml/roxml_builder.rb', line 75

def node_has_child?(node, child)
  @nodes[node.path] && @nodes[node.path][child]
end

#root_class_nameObject



20
21
22
# File 'lib/roundtrip_xml/roxml_builder.rb', line 20

def root_class_name
  name_to_sym @root.name
end