Class: ModelXML::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/model_xml/generator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGenerator

Returns a new instance of Generator.



11
12
13
# File 'lib/model_xml/generator.rb', line 11

def initialize
  @field_sets ||= []
end

Instance Attribute Details

#field_setsObject (readonly)

Returns the value of attribute field_sets.



9
10
11
# File 'lib/model_xml/generator.rb', line 9

def field_sets
  @field_sets
end

Instance Method Details

#add_field_set(*args, &block) ⇒ Object

three types of argument list are expected:

  1. an unnamed fieldset expressed as any number of symbols eg

model_xml :id, :first_name, :last_name, [:embossed_name, :getter => proc {|u| “#{u.first_name} #ModelXML::Generator.uu.last_name”.upcase}]

  1. a named fieldset in block notation eg

model_xml :personal_data do

:first_name
:last_name
:embossed_name proc {|u| "#{u.first_name} #{u.last_name}".upcase}

end

  1. an unnamed fieldset in block notation eg

model_xml do

:first_name
last_name

end



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/model_xml/generator.rb', line 33

def add_field_set *args, &block

  # if the argument list is empty and we have a block, it is an unnamed block
  if args.empty? && block_given?
    @field_sets << ModelXML::BlockParser.parse(&block)

  # otherwise if the argument list is a symbol and we have a block, it is a named block
  elsif args.map(&:class) == [Symbol] && block_given?
    name = args[0]
    @field_sets << {name => ModelXML::BlockParser.parse(&block)}

  # otherwise assume it is a simple fieldset expressed as symbols
  else
    @field_sets << args
  end
end

#generate_field_list(options = {}) ⇒ Object

apply any options to the default field sets to generate a single array of fields



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/model_xml/generator.rb', line 51

def generate_field_list options={}

  field_list = []
  @field_sets.each do |field_set|

    # if the field set is a hash then it is a hash of conditional field sets
    # which should only be included if the conditions are present as options
    if field_set.is_a?(Hash)
      field_set.each do |k, v|
        field_list += v if options[k]
      end

    # otherwise, always include
    else
      field_list += field_set
    end
  end
  field_list
end

#generate_xml!(object, options = {}) ⇒ Object



71
72
73
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/model_xml/generator.rb', line 71

def generate_xml! object, options={}

  field_list = generate_field_list(options)

  xml = options.delete(:builder) || Builder::XmlMarkup.new(:indent => 2)
  exceptions_list = options.delete(:except) || []
  limit_list = options.delete(:only)

  unless options[:skip_instruct]
    xml.instruct!
  end

  root_node = options[:root] || object.class.to_s
  root_node = root_node.demodulize if root_node.respond_to?(:demodulize) # Rails only
  root_node = root_node.underscore if root_node.respond_to?(:underscore) # Rails only

  xml.tag! root_node do

    field_list.each do |field|

      # if the field is a symbol, treat it as the field name and the getter method
      if field.is_a?(Symbol)
        tag = field
        content = object.send(field)

      # if the field is an array of a symbol followed by a proc, assume the symbol is the field name and the proc is the getter
      elsif field.is_a?(Array) && field.map(&:class) == [Symbol, Proc]
        tag = field[0]
        content = field[1].call(object)

      # otherwise we have garbage
      else
       raise "ModelXML unable to parse #{field.inspect}"
      end

      # ignore the tag if it is on the exclude list, or if a limit list is provided and it is not on it
      if exceptions_list.include?(tag) || (limit_list && !limit_list.include?(tag))
        # do nothing
      else

        # if the content responds to to_xml, call it passing the current builder
        if content.respond_to?(:to_xml)
          content.to_xml(options.merge(:builder => xml, :skip_instruct => true, :root => tag.to_s, :dasherize => false))

        # otherwise create the tag normally
        else
          xml.tag! tag, content
        end
      end
    end
  end

  xml.target!

end