Class: Exchanger::Element

Inherits:
Object
  • Object
show all
Includes:
Attributes, Dirty, Persistence
Defined in:
lib/exchanger/element.rb

Overview

General purpose element.

Direct Known Subclasses

Attendee, BaseFolder, CompleteName, Entry, Identifier, Item, Mailbox, SingleRecipient

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Persistence

#destroy, #new_record?, #reload, #save

Methods included from Dirty

#attribute_change, #attribute_changed?, #attribute_was, #changed, #changed?, #changes, included, #move_changes, #previous_changes, #reset_attribute!, #reset_modifications, #setup_modifications

Methods included from Attributes

#attributes, #attributes=, #change_key, #id, #identifier, #method_missing, #read_attribute, #respond_to?, #write_attribute

Constructor Details

- (Element) initialize(attributes = {})

A new instance of Element



45
46
47
48
49
# File 'lib/exchanger/element.rb', line 45

def initialize(attributes = {})
  @attributes = {}
  self.attributes = attributes
  setup_modifications
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Exchanger::Attributes

Instance Attribute Details

- (Object) tag_name



41
42
43
# File 'lib/exchanger/element.rb', line 41

def tag_name
  @tag_name || self.class.name.demodulize
end

Class Method Details

+ (Object) create_element_accessors(name)

Create child element accessors.



33
34
35
36
37
# File 'lib/exchanger/element.rb', line 33

def self.create_element_accessors(name)
  define_method(name) { read_attribute(name) }
  define_method("#{name}=") { |value| write_attribute(name, value) }
  define_method("#{name}?") { read_attribute(name).present? }
end

+ (Object) element(name, options = {})

Define a new child element.



18
19
20
21
22
23
# File 'lib/exchanger/element.rb', line 18

def self.element(name, options = {})
  options[:field_uri_namespace] ||= self.field_uri_namespace
  elements[name] = Field.new(name, options)
  create_element_accessors(name)
  add_dirty_methods(name)
end

+ (Object) key(name, options = {})

Defina a new element attribute.



26
27
28
29
30
# File 'lib/exchanger/element.rb', line 26

def self.key(name, options = {})
  keys << name
  create_element_accessors(name)
  add_dirty_methods(name)
end

+ (Object) new_from_xml(xml)



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/exchanger/element.rb', line 72

def self.new_from_xml(xml)
  object = new
  # Keys
  xml.attributes.values.each do |attr|
    name = attr.name.underscore.to_sym
    value = attr.value
    object.write_attribute(name, value)
  end
  # Fields
  xml.children.each do |node|
    name = node.name.underscore.to_sym
    field = elements[name] || Field.new(name)
    value = field.value_from_xml(node)
    object.write_attribute(name, value)
  end
  object.send(:reset_modifications)
  object
end

Instance Method Details

- (Object) ==(other)

Performs equality checking on attributes



52
53
54
55
# File 'lib/exchanger/element.rb', line 52

def ==(other)
  self.class == other.class &&
  self.attributes == other.attributes
end

- (Object) errors



57
58
59
# File 'lib/exchanger/element.rb', line 57

def errors
  @errors ||= []
end

- (Object) inspect



61
62
63
64
65
66
67
68
69
70
# File 'lib/exchanger/element.rb', line 61

def inspect
  keys = self.class.elements.keys | attributes.keys.map(&:to_sym)
  keys -= [:id, :change_key, self.class.identifier_name]
  attrs = keys.map { |name, field| "#{name}: #{attributes[name.to_s].inspect}" }
  str = "#<#{self.class.name}"
  str << " id: #{id.inspect}, change_key: #{change_key.inspect}" if self.class.identifier_name || self.class.keys.include?(:id)
  str << " #{attrs * ', '}" unless attrs.empty?
  str << ">"
  str
end

- (Object) to_xml(options = {})

Builds XML from elements and attributes



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/exchanger/element.rb', line 92

def to_xml(options = {})
  doc = Nokogiri::XML::Document.new
  root = doc.create_element(tag_name)
  self.class.keys.each do |name|
    value = read_attribute(name)
    next if value.blank?
    root[name.to_s.camelize] = value
  end
  self.class.elements.each do |name, field|
    next if options[:only] && !options[:only].include?(name)
    next if field.options[:readonly]
    value = read_attribute(name)
    next if field.type.is_a?(Array) && value.blank?
    next if new_record? && field.type == Identifier
    next if new_record? && value.blank?
    if name == :text
      root << value.to_s
    else
      root << field.to_xml(value)
    end
  end
  root
end

- (Object) to_xml_change

Builds XML Item/Folder change for update operations.



117
118
119
120
121
122
123
# File 'lib/exchanger/element.rb', line 117

def to_xml_change
  doc = Nokogiri::XML::Document.new
  root = doc.create_element("#{identifier.tag_name.gsub(/Id$/, '')}Change")
  root << identifier.to_xml
  root << to_xml_updates
  root
end

- (Object) to_xml_updates

Builds XML Set/Delete fields for update operations.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/exchanger/element.rb', line 126

def to_xml_updates
  doc = Nokogiri::XML::Document.new
  root = doc.create_element("Updates")
  self.class.elements.each do |name, field|
    value = read_attribute(name)
    # Create or update existing fields
    if changes.include?(name.to_s)
      field.to_xml_updates(value) do |field_uri_xml, element_xml|
        # Exchange does not like updating to nil, so delete those.
        if element_xml.text.present?
          set_item_field = doc.create_element("SetItemField")
          set_item_field << field_uri_xml
          element_wrapper = doc.create_element(tag_name)
          element_wrapper << element_xml
          set_item_field << element_wrapper
          root << set_item_field
        else
          delete_item_field = doc.create_element("DeleteItemField")
          delete_item_field << field_uri_xml
          root << delete_item_field
        end
      end
    end
    # Delete removed phone numbers, etc
    if changes.include?(name.to_s) && value.is_a?(Array)
      old_values, new_values = changes[name.to_s]
      deleted_values = old_values - new_values
      field.to_xml_updates(deleted_values) do |field_uri_xml, _|
        delete_item_field = doc.create_element("DeleteItemField")
        delete_item_field << field_uri_xml
        root << delete_item_field
      end
    end
  end
  root
end