Class Adaptation::Message
In: lib/adaptation/message.rb
Parent: Object

Adaptation::Message — XML to classes mapping.

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:

  • Automated mapping between classes and xml attributes and elements.
       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

  • Associations between objects controlled by simple meta-programming macros.
       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>
    
  • Validation rules.

    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
    

Methods

Included Modules

Validateable ROXML

Attributes

id  [R] 

Public Class methods

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

Returns the xml element this class is mapping

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>")

Public Instance methods

Alias for Adaptation::Message#valid? Deprecated, use valid? instead.

[Validate]