| Class | Adaptation::Message |
| In: |
lib/adaptation/message.rb
|
| Parent: | Object |
Adaptation::Message connects ruby objects and xml data to create a model where logic and data are presented in one wrapping. It‘s is inspired on activerecord, and pretends to solve xml data management problems in a similar way activerecord handles database data management.
Adaptation::Message classes describe xml structures, allowing separation of common structures as standalone classes. It offers a set of macros to specify wich structures are part of a bigger one and to allow validation of the different parts.
A summary of the major features and their usage:
class Contact < Adaptation::Message
has_one :text, :name
end
…is automatically mapped to a xml structure with root element named "contact", such as:
<contact>
<name>Name</name>
</contact>
…which gives Contact#name
class Agenda < Adaptation::Message
has_one :attribute, :type
has_one :text, :owner
has_many :contacts
end
class Contact < Adaptation::Message
has_one :text, :name
end
Agenda class would be mapping the following xml structure:
<agenda type="...">
<owner>...</owner>
<contact>...</contact>
<contact>...</contact>
...
</agenda>
while the Contact class would map:
<contact>
<name>...</name>
</contact>
The Contact class is a partial, a structure included in a bigger structure, so its file name starts with an underscore: _contact.rb
We could have wrote Agenda like this, to change the contacts container name:
class Agenda < Adaptation::Message
has_one :attribute, :type
has_one :text, :owner
has_many :contacts, :in => :contact_list
end
and Contact like:
class Contact < Adaptation::Message
has_one :text, :name
end
Then the mapping in Agenda would be:
<agenda type="...">
<owner>...</owner>
<contact_list>
<contact>...</contact>
</contact_list>
</agenda>
Adaptation::Message uses ActiveRecord::Validations. This means that ActiveRecord validations can be used in an Adaptation::Message object and that custom validations can be easily implemented.
Adaptation::Message also defines some custom validation methods.
Validations usage example:
class Agenda < Adaptation::Message
has_one :attribute, :type
has_one :text, :owner
validates_presence_of :owner, :type
validates_value_of :type, "indexed"
end
| id | [R] |
Maps many xml subelements.
Example 1:
<xml>
<subelement>...</subelement>
<subelement>...</subelement>
<subelement>...</subelement>
</xml>
class Xml < Adaptation::Message
has_many :subelements
end
Example 2:
<xml>
<subelement_list>
<subelement>...</subelement>
<subelement>...</subelement>
<subelement>...</subelement>
</subelement_list>
</xml>
class Xml < Adaptation::Message
has_many :subelements, :in => :subelement_list
end
Maps an xml attribute or element.
Example 1: Mapping an attribute:
<xml attr="something"/>
class Xml < Adaptation::Message
has_one :attribute, :attr
end
Example 2: Mapping an xml element that contains text.
<xml>
<element>something</element>
</xml>
class Xml < Adaptation::Message
has_one :text, :element
end
Example 3: Mapping an xml element that contains xml data.
<xml>
<element>
<subelement>something</subelement>
</element>
</xml>
class Xml < Adaptation::Message
has_one :object, :element
end
The element xml structure would be described in a separate partial file _element.rb:
class Element < Adaptation::Message
has_one :text, :subelement
end
Maps an xml element text.
If an element contains plain text data and has not been declared in its parent element with has_one :text, it must declare itself with has_text to be able to contain text.
Example:
<xml>
<element attr="something">something more</element>
</xml>
class Xml < Adaptation::Message
has_one :object, :element
end
In this case element cannot be declared just like has_one :text, because it also has an attribute. It must be declared like has_one :object. Then the element declares itself in a file called _element.rb like this:
class Element < Adaptation::Message
has_one :attribute, :attr
has_text
end
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
This is the constructor. Instead of Adaptation::Message#new, an Adaptation::Message instance is created like this:
m = Adaptation::Message.to_object("<xml>valid xml</xml>")