-
Notifications
You must be signed in to change notification settings - Fork 0
Syntax
To define maps one need to add them to the catalogue, to do it call Mappum.catalogue_add function:
Mappum.catalogue_add do
- … maps go here …
end
Mappum.catalogue_add has one optional argument – catalogue name (defaults to ROOT) do one can call it like this:
Mappum.catalogue_add "SOME_NAME" do
… maps go here …
end
To define mapping between two documents be it XML or Ruby objects you need to call map function. Like this:
map Person, Client do |person_alias, client_alias|
#... submaps go here ...
end
One can use symbols instead of class names for example :Person instead of Person.
Be careful! It is not possible now to use Person <=> CRM::Client syntax here, we know that it would be nice but have no idea how to fix it.
By default maps are given names as follows:
- For bidirectional maps: Type1_from_to_Type2
- For unidirectional maps: Type1_to_Type2
One can use name_map or name_map_prefix method to change names of maps:
map Person, Client do |person_alias, client_alias| #not a recommended name name_map '<', 'person_from_client' #a recommended name name_map '<=>', 'Nolists_Person_to_from_Client' #prefix works only for default names name_map_prefix 'Nolists_' end
Maps are also looked up by class name of from and to mappings if this mappings are unique by catalogue.
To map (or bind) two elements of the structure you write:
person_alias.element1 <=> client_alias.element2
This will transform element1 from Person to element2 on Client when transforming Person to Client. And transform element2 from Client to element1 on Person when transforming Client to Person. We say transform instead of copy but it will be copied when types of elements are the same. If types are not same and no sub-map is defined map from catalogue for given types will be used.
When type will not be deduced from object definition (in runtime) one need to declare type of element. This is done like this:
map p.address(ERP::Address) <=> c.address(CRM::Address)
When the map for this classes is declared in same catalogue it will be processed automatically. Maps for some typical conversions are defined in autoconv_catalogue and used by default, currently there are such a conversions defined:
| Conversion | Mappum version | Remarks |
|---|---|---|
| Date <=> String | >=0.2 | The format used is YYYY-MM-DD |
| Time <=> String | >=0.2 | Format rfc2822 is used in Time >> String conversion |
| Float <=> String | >=0.2 | |
| Fixnum <=> String | >=0.2 |
To change the default conversion define your own map for given types in chosen catalogue. For example to change default time format to iso8601 do:
Mappum.catalogue_add
map Time, String do |a,b|
map a.self << b.self do |b1|
return Time.parse(b1)
end
map a.self.iso8601 >> b.self
end
end
and use it like this:
Mappum.catalogue_add
map Xo, Yo do |x,y|
x.my_time(Time) <=> y.your_time(String)
end
end
If you like to change the way object are converted for one mapping only you should do:
Mappum.catalogue_add
map Xo, Yo do |x,y|
`leave default`
x.my_time(Time) << y.your_time(String)
`go utc and iso`
x.my_time.getutc.iso8601 >> y.your_time
end
end
Maps of substructures e.g. complex elements can be declared in line as sub-maps. Sub map is a do .. end block given to map function:
map p.address(ERP::Address) <=> c.address(CRM::Address) do |erp_address, crm_address|
map erp_address.street <=> crm_address.street
#etc.
end
Maps can point one direction only:
map p.text >> c.body
#or
map p.somefield << c.element
This map will work as normal bidirectional map when object will be transformed but:
- There is no sub-maps on unidirectional maps
- You can declare function calls on unidirectional maps
Function calls work only on unidirectional maps. To call a function on mapped object simply add call after the element:
map p.text.upcase >> c.body
#or
map p.somefield << c.element[0..5]
Function calls work only on unidirectional maps. To execute multiline Ruby code on element pass block of code to map function:
map p.text >> c.body do |text|
return text.upcase
end
#or
map p.somefield << c.element do |elem|
return elem[0..5]
end
Constant values can be mapped to fields in both directions. One need to specify the constant value
in the unidirectional map.
map p.type << "NaN"
map "Last" >> c.order_by
To provide the function with no arguments (named raw in here) to be evaluated in the moment of
mapping “func” keyword is used.
map p.date_updated << func do
Date.today
end
map func >> c.updated do
Time.now
end
Dictionaries support bidirectional mapping. When mapping left to right element value matching key in the dictionary will be mapped to value for that key. And when mapping right to left element value matching value from dictionary will be mapped to the matching key.
map p.name <=> c.sn, :dict => {"PTO" => "Point to Object", "B2B" => "Business to Business"}
One can pass a context (an arbitrary object) to transform function in options parameter as {:context => ctx}. Then in the map use context as any other element:
map context.session["username"] <=> c.user
map context.ip <=> c.server
When mapping Hash to non hash. One can use [key]. An example is:
map p.props["username"] <=> c.user
When mapping Arrays to non arrays. One can use find{|elem| block}. An example of use with sub-maps on typical
properties list:
map p.group <=> c.properties.find{|prop| prop.name == "group"} do |group, prop|
map group.self <=> prop.value
map "group" >> prop.name
end
When mapping from p → c on non nil group element property with name “group” and value of p.group field will be added to properties list. When mapping from c → p property with name “group” will be found and its value will be mapped to p.group.
When mapping array to array one can use select function select{|elem| conditon} to filter from lists.
By default when mapping to same array second time new element will be appended to this array. One can change this by using
to_array_take method.
First argument is a label:
:> – left to right map
:< – right to left map
:<=> – both maps
Second argument is the_way and can be:
:new – will create new element
:first – will map to the first element
:all – will map to all elements
map c.products[] <=> d.products[] do |wn, app|
...
end
map c.default_product <=> d.products[] do |wn, app|
to_array_take :>, :all
...
end
If the map is to be executed only on certain conditions one can use map_when method for bidirectional maps and :when parameter for unidirectional.
map f.mem <=> b.tem do
map_when(:>) {|mem| mem > 10}
end
map f.mem <=> b.gem do
map_when(:>) {|mem| mem <= 10}
end
map f.pol >> b.gol, :when => lambda {|pol| pol != 0}
Attributes are accessible via xmlattr_ prefix.
map p.xmlattr_name <=> c.name