Class: Adaptation::Message
- Includes:
- Validateable
- Defined in:
- lib/adaptation/message.rb
Overview
Adaptation::Message – XML to classes mapping.
Adaptation::Message maps xml data into a ruby object. It also provides validators (inspired by ActiveRecord ORM) to check xml format.
Examples:
contact = Adaptation::Message.new('<contact><name kind="surname">Name</name></contact>')
contact.name.content # -> "Name"
contact.names.first.content # -> "Name"
contact.names.length # -> 1
contact.name.kind # -> "surname"
Let’s add some validations:
class Contact < Adaptation::Message
validates_presence_of :name
end
contact = Contact.new('<contact><name kind="surname">Name</name></contact>')
contact.valid? # -> true
contact = Contact.new('<contact><phone>555</phone></contact>')
contact.valid? # -> false
class SeriousContact < Adaptation::Message
maps_xml :contact # tell Adaptation that xml data like <contact>...</contact> is mapped by this class
validates_value_of :kind, "surname", :in => :names
end
contact = SeriousContact.new('<contact><name kind="surname">Name</name></contact>')
contact.valid? # -> true
contact = SeriousContact.new('<contact><name kind="alias">Alias</name></contact>')
contact.valid? # -> false
More on validations here.
Constant Summary collapse
- @@classes_with_brothers =
[]
Instance Attribute Summary collapse
-
#id ⇒ Object
readonly
avoid id method deprecation warnings.
Class Method Summary collapse
-
.get_class_object(mapped_xml) ⇒ Object
:nodoc:.
-
.has_many(*options) ⇒ Object
:nodoc:.
-
.has_one(*symbols) ⇒ Object
:nodoc:.
-
.has_text ⇒ Object
:nodoc:.
-
.logger ⇒ Object
:nodoc:#.
-
.mapped_xml ⇒ Object
Returns the xml element this class is mapping.
-
.maps_xml(element) ⇒ Object
Defines the xml element that this class is mapping.
-
.to_object(xml_message) ⇒ Object
Deprecated, use new instead.
Instance Method Summary collapse
-
#check ⇒ Object
Deprecated, use valid? instead.
-
#initialize(xml_string) ⇒ Message
constructor
Constructor.
- #to_hash ⇒ Object
- #to_xml ⇒ Object
Methods included from Validateable
append_features, included, #method_missing
Constructor Details
#initialize(xml_string) ⇒ Message
Constructor. Transforms xml passsed as a String to an object wich methods map the input xml elements and attributes.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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 |
# File 'lib/adaptation/message.rb', line 56 def initialize xml_string @hash_with_root = XmlSimple.xml_in("<adaptation_wrapper>" + xml_string + "</adaptation_wrapper>", 'ForceArray' => false, 'AttrPrefix' => true) first_value = @hash_with_root.values.first hash = first_value.is_a?(String) ? {"content" => first_value} : first_value array = hash.is_a?(Array) ? hash : [hash] array.each do |h| if end_of_tree?(h) h.each_pair do |k, v| if !v.is_a?(Array) is_attribute = k.include?("@") ? true : false var = k.gsub("@","") self.class_eval "attr_accessor :#{var}" eval "@#{var} = v" var2 = pluralize(var) if !is_attribute and var != var2 self.class_eval "attr_accessor :#{var2}" eval "@#{var2} = []; @#{var2} << '#{var}'" end else var = pluralize(k.gsub("@","")) self.class_eval "attr_accessor :#{var}" eval "@#{var} = []" v.each do |val| if is_attribute?(val) xml_substring = XmlSimple.xml_out(val, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true) eval "@#{var} << Adaptation::Message.new('#{xml_substring}')" else eval "@#{var} << '#{val}'" end end end end else h.each_pair do |k,v| if k[0..0] == "@" var = k.gsub("@","") self.class_eval "attr_accessor :#{var}" eval "@#{var} = '#{v}'" else self.class_eval "attr_accessor :#{k}" xml_substring = "" if !v.is_a?(Array) xml_substring = XmlSimple.xml_out(v, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true) eval "@#{k} = Adaptation::Message.new('#{xml_substring}')" k2 = pluralize(k) if k != k2 self.class_eval "attr_accessor :#{k2}" eval "@#{k2} = []; @#{k2} << @#{k}" end else k2 = pluralize(k) self.class_eval "attr_accessor :#{k2}" eval "@#{k2} = [];" v.each do |val| xml_substring = XmlSimple.xml_out(val, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true) eval "@#{k} = Adaptation::Message.new('#{xml_substring}')" eval "@#{k2} << @#{k}" end end end end end end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Validateable
Instance Attribute Details
#id ⇒ Object (readonly)
avoid id method deprecation warnings
47 48 49 |
# File 'lib/adaptation/message.rb', line 47 def id @id end |
Class Method Details
.get_class_object(mapped_xml) ⇒ Object
:nodoc:
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/adaptation/message.rb', line 173 def self.get_class_object(mapped_xml) #:nodoc: # TODO: reimplement this as read in ruby-talk (using 'inherited' method) mapped_xml = mapped_xml.downcase.to_sym if mapped_xml.is_a?(String) klass = nil ObjectSpace.each_object(Class) do |c| next unless c.ancestors.include?(Adaptation::Message) and (c != self) and (c != Adaptation::Message) (klass = c and break) if c.mapped_xml == mapped_xml rescue next end klass end |
.has_many(*options) ⇒ Object
:nodoc:
132 133 134 |
# File 'lib/adaptation/message.rb', line 132 def self.has_many * #:nodoc: logger.info "has_many is deprecated and not necessary" end |
.has_one(*symbols) ⇒ Object
:nodoc:
124 125 126 |
# File 'lib/adaptation/message.rb', line 124 def self.has_one *symbols #:nodoc: logger.info "has_one is deprecated and not necessary" end |
.has_text ⇒ Object
:nodoc:
128 129 130 |
# File 'lib/adaptation/message.rb', line 128 def self.has_text #:nodoc: logger.info "has_text is deprecated and not necessary" end |
.logger ⇒ Object
:nodoc:#
196 197 198 |
# File 'lib/adaptation/message.rb', line 196 def self.logger#:nodoc:# Adaptation::Base.logger rescue Logger.new(STDOUT) end |
.mapped_xml ⇒ Object
Returns the xml element this class is mapping
169 170 171 |
# File 'lib/adaptation/message.rb', line 169 def self.mapped_xml @mapped_xml || self.to_s.downcase.gsub("::","_").to_sym end |
.maps_xml(element) ⇒ Object
Defines the xml element that this class is mapping. This is useful to avoid class name collisions:
Example:
We already have a database table called 'things' and we
interoperate with it with an ActiveRecord subclass called
'Thing':
class Thing < ActiveRecord::Base
...
end
But in the same Adaptation application we want to parse the
following xml:
<thing>...</thing>
Defining another class Thing would produce a class name
collision, but we can do:
class XmlThing < Adaptation::Message
maps_xml :thing
...
end
and store it in a file called app/messages/thing.rb
164 165 166 |
# File 'lib/adaptation/message.rb', line 164 def self.maps_xml element @mapped_xml = element end |
.to_object(xml_message) ⇒ Object
Deprecated, use new instead.
185 186 187 188 |
# File 'lib/adaptation/message.rb', line 185 def self.to_object #:nodoc: logger.info "to_object is deprecated, use new instead" self.new() end |
Instance Method Details
#check ⇒ Object
Deprecated, use valid? instead.
191 192 193 194 |
# File 'lib/adaptation/message.rb', line 191 def check #:nodoc: logger.info "check is deprecated, use valid? instead" valid? end |
#to_hash ⇒ Object
204 205 206 |
# File 'lib/adaptation/message.rb', line 204 def to_hash @hash_with_root end |
#to_xml ⇒ Object
200 201 202 |
# File 'lib/adaptation/message.rb', line 200 def to_xml xml_out(@hash_with_root).gsub("\"","'").gsub(/(<|<\/)content(>| *\/>)/,"") end |