xmlmapper 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +35 -0
- data/README.md +605 -0
- data/lib/happymapper.rb +776 -0
- data/lib/happymapper/anonymous_mapper.rb +114 -0
- data/lib/happymapper/attribute.rb +21 -0
- data/lib/happymapper/element.rb +55 -0
- data/lib/happymapper/item.rb +160 -0
- data/lib/happymapper/supported_types.rb +140 -0
- data/lib/happymapper/text_node.rb +8 -0
- data/lib/happymapper/version.rb +3 -0
- data/lib/xmlmapper.rb +1 -0
- data/spec/attribute_default_value_spec.rb +50 -0
- data/spec/attributes_spec.rb +36 -0
- data/spec/fixtures/address.xml +9 -0
- data/spec/fixtures/ambigous_items.xml +22 -0
- data/spec/fixtures/analytics.xml +61 -0
- data/spec/fixtures/analytics_profile.xml +127 -0
- data/spec/fixtures/atom.xml +19 -0
- data/spec/fixtures/commit.xml +52 -0
- data/spec/fixtures/current_weather.xml +89 -0
- data/spec/fixtures/current_weather_missing_elements.xml +18 -0
- data/spec/fixtures/default_namespace_combi.xml +6 -0
- data/spec/fixtures/dictionary.xml +20 -0
- data/spec/fixtures/family_tree.xml +21 -0
- data/spec/fixtures/inagy.xml +85 -0
- data/spec/fixtures/lastfm.xml +355 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/multiple_primitives.xml +5 -0
- data/spec/fixtures/optional_attributes.xml +6 -0
- data/spec/fixtures/pita.xml +133 -0
- data/spec/fixtures/posts.xml +23 -0
- data/spec/fixtures/product_default_namespace.xml +18 -0
- data/spec/fixtures/product_no_namespace.xml +10 -0
- data/spec/fixtures/product_single_namespace.xml +10 -0
- data/spec/fixtures/quarters.xml +19 -0
- data/spec/fixtures/radar.xml +21 -0
- data/spec/fixtures/set_config_options.xml +3 -0
- data/spec/fixtures/statuses.xml +422 -0
- data/spec/fixtures/subclass_namespace.xml +50 -0
- data/spec/fixtures/wrapper.xml +11 -0
- data/spec/happymapper/attribute_spec.rb +12 -0
- data/spec/happymapper/element_spec.rb +9 -0
- data/spec/happymapper/item_spec.rb +115 -0
- data/spec/happymapper/text_node_spec.rb +9 -0
- data/spec/happymapper_parse_spec.rb +113 -0
- data/spec/happymapper_spec.rb +1116 -0
- data/spec/has_many_empty_array_spec.rb +43 -0
- data/spec/ignay_spec.rb +95 -0
- data/spec/inheritance_spec.rb +107 -0
- data/spec/mixed_namespaces_spec.rb +61 -0
- data/spec/parse_with_object_to_update_spec.rb +111 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/to_xml_spec.rb +200 -0
- data/spec/to_xml_with_namespaces_spec.rb +231 -0
- data/spec/wilcard_tag_name_spec.rb +96 -0
- data/spec/wrap_spec.rb +82 -0
- data/spec/xpath_spec.rb +89 -0
- metadata +182 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Sheep
|
4
|
+
class Item
|
5
|
+
include HappyMapper
|
6
|
+
end
|
7
|
+
|
8
|
+
class Navigator
|
9
|
+
include HappyMapper
|
10
|
+
tag 'navigator'
|
11
|
+
|
12
|
+
# This is purposefully set to have the name 'items' with the tag 'item'.
|
13
|
+
# The idea is that it should not find the empty items contained within the
|
14
|
+
# xml and return an empty array. This exercises the order of how nodes
|
15
|
+
# are searched for within an XML document.
|
16
|
+
has_many :items, Item, tag: 'item'
|
17
|
+
|
18
|
+
has_many :items_with_a_different_name, Item, tag: 'item'
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "emptyness" do
|
24
|
+
let(:xml) do
|
25
|
+
<<-EOF
|
26
|
+
<navigator>
|
27
|
+
<items/>
|
28
|
+
</navigator>
|
29
|
+
EOF
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:navigator) do
|
33
|
+
Sheep::Navigator.parse(xml)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns an empty array" do
|
37
|
+
navigator.items_with_a_different_name.should be_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns an empty array" do
|
41
|
+
navigator.items.should be_empty
|
42
|
+
end
|
43
|
+
end
|
data/spec/ignay_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CatalogTree
|
4
|
+
include HappyMapper
|
5
|
+
|
6
|
+
tag 'CatalogTree'
|
7
|
+
register_namespace 'xmlns', 'urn:eventis:prodis:onlineapi:1.0'
|
8
|
+
register_namespace 'xsi', 'http://www.w3.org/2001/XMLSchema-instance'
|
9
|
+
register_namespace 'xsd', 'http://www.w3.org/2001/XMLSchema'
|
10
|
+
|
11
|
+
attribute :code, String
|
12
|
+
|
13
|
+
has_many :nodes, 'CatalogNode', :tag => 'Node', :xpath => '.'
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class CatalogNode
|
19
|
+
include HappyMapper
|
20
|
+
|
21
|
+
tag 'Node'
|
22
|
+
|
23
|
+
attribute :back_office_id, String, :tag => 'vodBackOfficeId'
|
24
|
+
|
25
|
+
has_one :name, String, :tag => 'Name'
|
26
|
+
# other important fields
|
27
|
+
|
28
|
+
has_many :translations, 'CatalogNode::Translations', :tag => 'Translation', :xpath => 'child::*'
|
29
|
+
|
30
|
+
class Translations
|
31
|
+
include HappyMapper
|
32
|
+
tag 'Translation'
|
33
|
+
|
34
|
+
attribute :language, String, :tag => 'Language'
|
35
|
+
has_one :name, String, :tag => 'Name'
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
has_many :nodes, CatalogNode, :tag => 'Node', :xpath => 'child::*'
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe HappyMapper do
|
44
|
+
|
45
|
+
it "should not be nil" do
|
46
|
+
catalog_tree.should_not be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should have the attribute code" do
|
50
|
+
catalog_tree.code.should == "NLD"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have many nodes" do
|
54
|
+
catalog_tree.nodes.should_not be_empty
|
55
|
+
catalog_tree.nodes.length.should == 2
|
56
|
+
end
|
57
|
+
|
58
|
+
context "first node" do
|
59
|
+
|
60
|
+
it "should have a name" do
|
61
|
+
first_node.name.should == "Parent 1"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have translations" do
|
65
|
+
first_node.translations.length.should == 2
|
66
|
+
|
67
|
+
first_node.translations.first.language.should == "en-GB"
|
68
|
+
|
69
|
+
first_node.translations.last.name.should == "Parent 1 de"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have subnodes" do
|
73
|
+
first_node.nodes.should be_kind_of(Enumerable)
|
74
|
+
first_node.nodes.should_not be_empty
|
75
|
+
first_node.nodes.length.should == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
it "first node - first node name" do
|
79
|
+
first_node.nodes.first.name.should == "First"
|
80
|
+
end
|
81
|
+
|
82
|
+
def first_node
|
83
|
+
@first_node = catalog_tree.nodes.first
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def catalog_tree ; @catalog_tree ; end
|
90
|
+
|
91
|
+
before(:all) do
|
92
|
+
xml_reference = "#{File.dirname(__FILE__)}/fixtures/inagy.xml"
|
93
|
+
@catalog_tree = CatalogTree.parse(File.read(xml_reference), :single => true)
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Using inheritance to share elements and attributes" do
|
4
|
+
|
5
|
+
class Genetics
|
6
|
+
include HappyMapper
|
7
|
+
content :dna, String
|
8
|
+
end
|
9
|
+
|
10
|
+
class Parent
|
11
|
+
include HappyMapper
|
12
|
+
attribute :love, Integer
|
13
|
+
element :genetics, Genetics
|
14
|
+
end
|
15
|
+
|
16
|
+
class Child < Parent
|
17
|
+
include HappyMapper
|
18
|
+
attribute :naivety, String
|
19
|
+
has_many :immunities, String
|
20
|
+
end
|
21
|
+
|
22
|
+
class Overwrite < Parent
|
23
|
+
include HappyMapper
|
24
|
+
|
25
|
+
attribute :love, String
|
26
|
+
element :genetics, Integer
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "Overwrite" do
|
30
|
+
let(:subject) do
|
31
|
+
xml = '<overwrite love="love" naivety="trusting"><genetics>1001</genetics><immunities>Chicken Pox</immunities></overwrite>'
|
32
|
+
Overwrite.parse(xml, single: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'overrides the parent elements and attributes' do
|
36
|
+
expect(Overwrite.attributes.count).to be == Parent.attributes.count
|
37
|
+
expect(Overwrite.elements.count).to be == Parent.elements.count
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when parsing xml" do
|
41
|
+
it 'parses the new overwritten attribut' do
|
42
|
+
expect(subject.love).to be == "love"
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'parses the new overwritten element' do
|
46
|
+
expect(subject.genetics).to be == 1001
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when saving to xml" do
|
51
|
+
subject do
|
52
|
+
overwrite = Overwrite.new
|
53
|
+
overwrite.genetics = 1
|
54
|
+
overwrite.love = "love"
|
55
|
+
Nokogiri::XML(overwrite.to_xml).root
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'has only 1 genetics element' do
|
59
|
+
expect(subject.xpath('//genetics').count).to be == 1
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'has only 1 love attribute' do
|
63
|
+
expect(subject.xpath('@love').text).to be == "love"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "Child", "a subclass of the Parent" do
|
69
|
+
let(:subject) do
|
70
|
+
xml = '<child love="99" naivety="trusting"><genetics>ABBA</genetics><immunities>Chicken Pox</immunities></child>'
|
71
|
+
Child.parse(xml)
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when parsing xml" do
|
75
|
+
it 'should be possible to deserialize XML into a Child class instance' do
|
76
|
+
expect(subject.love).to eq 99
|
77
|
+
expect(subject.genetics.dna).to eq "ABBA"
|
78
|
+
expect(subject.naivety).to eq "trusting"
|
79
|
+
expect(subject.immunities).to have(1).item
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when saving to xml" do
|
84
|
+
let(:subject) do
|
85
|
+
child = Child.new
|
86
|
+
child.love = 100
|
87
|
+
child.naivety = 'Bright Eyed'
|
88
|
+
child.immunities = [ "Small Pox", "Chicken Pox", "Mumps" ]
|
89
|
+
genetics = Genetics.new
|
90
|
+
genetics.dna = "GATTACA"
|
91
|
+
child.genetics = genetics
|
92
|
+
Nokogiri::XML(child.to_xml).root
|
93
|
+
end
|
94
|
+
|
95
|
+
it "saves both the Child and Parent attributes" do
|
96
|
+
expect(subject.xpath("@naivety").text).to eq "Bright Eyed"
|
97
|
+
expect(subject.xpath("@love").text).to eq "100"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "saves both the Child and Parent elements" do
|
101
|
+
expect(subject.xpath("genetics").text).to eq "GATTACA"
|
102
|
+
expect(subject.xpath("immunities")).to have(3).items
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A document with mixed namespaces" do
|
4
|
+
|
5
|
+
#
|
6
|
+
# Note that the parent element of the xml has the namespacing. The elements
|
7
|
+
# contained within the xml do not share the parent element namespace so a
|
8
|
+
# user of the library would likely need to clear the namespace on each of
|
9
|
+
# these child elements.
|
10
|
+
#
|
11
|
+
let(:xml_document) do
|
12
|
+
%{<prefix:address location='home' xmlns:prefix="http://www.unicornland.com/prefix"
|
13
|
+
xmlns:different="http://www.trollcountry.com/different">
|
14
|
+
<street>Milchstrasse</street>
|
15
|
+
<street>Another Street</street>
|
16
|
+
<housenumber>23</housenumber>
|
17
|
+
<different:postcode>26131</different:postcode>
|
18
|
+
<city>Oldenburg</city>
|
19
|
+
</prefix:address>}
|
20
|
+
end
|
21
|
+
|
22
|
+
module MixedNamespaces
|
23
|
+
class Address
|
24
|
+
include HappyMapper
|
25
|
+
|
26
|
+
namespace :prefix
|
27
|
+
tag :address
|
28
|
+
|
29
|
+
# Here each of the elements have their namespace set to nil to reset their
|
30
|
+
# namespace so that it is not the same as the prefix namespace
|
31
|
+
|
32
|
+
has_many :streets, String, tag: 'street', namespace: nil
|
33
|
+
|
34
|
+
has_one :house_number, String, tag: 'housenumber', namespace: nil
|
35
|
+
has_one :postcode, String, namespace: 'different'
|
36
|
+
has_one :city, String, namespace: nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:address) do
|
41
|
+
MixedNamespaces::Address.parse(xml_document, single: true)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it "has the correct streets" do
|
46
|
+
expect(address.streets).to eq [ "Milchstrasse", "Another Street" ]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "house number" do
|
50
|
+
expect(address.house_number).to eq "23"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "postcode" do
|
54
|
+
expect(address.postcode).to eq "26131"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "city" do
|
58
|
+
expect(address.city).to eq "Oldenburg"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Updating existing objects with .parse and #parse" do
|
4
|
+
|
5
|
+
let(:subject) { ParseInstanceSpec::Root.parse(parse_instance_initial_xml) }
|
6
|
+
|
7
|
+
let(:parse_instance_initial_xml) do
|
8
|
+
%{<root attr1="initial">
|
9
|
+
<item attr1="initial">
|
10
|
+
<description>initial</description>
|
11
|
+
<subitem attr1="initial">
|
12
|
+
<name>initial</name>
|
13
|
+
</subitem>
|
14
|
+
<subitem attr1="initial">
|
15
|
+
<name>initial</name>
|
16
|
+
</subitem>
|
17
|
+
</item>
|
18
|
+
<item attr1="initial">
|
19
|
+
<description>initial</description>
|
20
|
+
<subitem attr1="initial">
|
21
|
+
<name>initial</name>
|
22
|
+
</subitem>
|
23
|
+
<subitem attr1="initial">
|
24
|
+
<name>initial</name>
|
25
|
+
</subitem>
|
26
|
+
</item>
|
27
|
+
</root>}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:parse_instance_updated_xml) do
|
31
|
+
%{<root attr1="updated">
|
32
|
+
<item attr1="updated">
|
33
|
+
<description>updated</description>
|
34
|
+
<subitem attr1="updated">
|
35
|
+
<name>updated</name>
|
36
|
+
</subitem>
|
37
|
+
<subitem attr1="updated">
|
38
|
+
<name>updated</name>
|
39
|
+
</subitem>
|
40
|
+
</item>
|
41
|
+
<item attr1="updated">
|
42
|
+
<description>updated</description>
|
43
|
+
<subitem attr1="updated">
|
44
|
+
<name>updated</name>
|
45
|
+
</subitem>
|
46
|
+
<subitem attr1="updated">
|
47
|
+
<name>updated</name>
|
48
|
+
</subitem>
|
49
|
+
</item>
|
50
|
+
</root>}
|
51
|
+
end
|
52
|
+
|
53
|
+
module ParseInstanceSpec
|
54
|
+
class SubItem
|
55
|
+
include HappyMapper
|
56
|
+
tag 'subitem'
|
57
|
+
attribute :attr1, String
|
58
|
+
element :name, String
|
59
|
+
end
|
60
|
+
class Item
|
61
|
+
include HappyMapper
|
62
|
+
tag 'item'
|
63
|
+
attribute :attr1, String
|
64
|
+
element :description, String
|
65
|
+
has_many :sub_items, SubItem
|
66
|
+
end
|
67
|
+
class Root
|
68
|
+
include HappyMapper
|
69
|
+
tag 'root'
|
70
|
+
attribute :attr1, String
|
71
|
+
has_many :items, Item
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def item_is_correctly_defined(item,value='initial')
|
76
|
+
expect(item.attr1).to eq value
|
77
|
+
expect(item.description).to eq value
|
78
|
+
expect(item.sub_items[0].attr1).to eq value
|
79
|
+
expect(item.sub_items[0].name).to eq value
|
80
|
+
expect(item.sub_items[1].attr1).to eq value
|
81
|
+
expect(item.sub_items[1].name).to eq value
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'initial values are correct' do
|
85
|
+
subject.attr1.should == 'initial'
|
86
|
+
item_is_correctly_defined( subject.items[0] )
|
87
|
+
item_is_correctly_defined( subject.items[1] )
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
describe ".parse", "specifying an existing object to update" do
|
92
|
+
it 'all fields are correct' do
|
93
|
+
ParseInstanceSpec::Root.parse(parse_instance_updated_xml, :update => subject)
|
94
|
+
expect(subject.attr1).to eq 'updated'
|
95
|
+
|
96
|
+
item_is_correctly_defined( subject.items[0], 'updated' )
|
97
|
+
item_is_correctly_defined( subject.items[1], 'updated' )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#parse" do
|
102
|
+
it "all fields are correct" do
|
103
|
+
subject.parse(parse_instance_updated_xml)
|
104
|
+
expect(subject.attr1).to eq 'updated'
|
105
|
+
|
106
|
+
item_is_correctly_defined( subject.items[0], 'updated' )
|
107
|
+
item_is_correctly_defined( subject.items[1], 'updated' )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/to_xml_spec.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Saving #to_xml" do
|
4
|
+
|
5
|
+
module ToXML
|
6
|
+
class Address
|
7
|
+
include HappyMapper
|
8
|
+
|
9
|
+
tag 'address'
|
10
|
+
|
11
|
+
attribute :location, String, :on_save => :when_saving_location
|
12
|
+
|
13
|
+
element :street, String
|
14
|
+
element :postcode, String
|
15
|
+
element :city, String
|
16
|
+
|
17
|
+
element :housenumber, String
|
18
|
+
|
19
|
+
attribute :modified, Boolean, :read_only => true
|
20
|
+
element :temporary, Boolean, :read_only => true
|
21
|
+
#
|
22
|
+
# to_xml will default to the attr_accessor method and not the attribute,
|
23
|
+
# allowing for that to be overwritten
|
24
|
+
#
|
25
|
+
def housenumber
|
26
|
+
"[#{@housenumber}]"
|
27
|
+
end
|
28
|
+
|
29
|
+
def when_saving_location(loc)
|
30
|
+
loc + "-live"
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Write a empty element even if this is not specified
|
35
|
+
#
|
36
|
+
element :description, String, :state_when_nil => true
|
37
|
+
|
38
|
+
#
|
39
|
+
# Perform the on_save operation when saving
|
40
|
+
#
|
41
|
+
has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
|
42
|
+
|
43
|
+
|
44
|
+
#
|
45
|
+
# Execute the method with the same name
|
46
|
+
|
47
|
+
#
|
48
|
+
# Write multiple elements and call on_save when saving
|
49
|
+
#
|
50
|
+
has_many :dates_updated, Time, :on_save => lambda {|times|
|
51
|
+
times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
|
52
|
+
|
53
|
+
#
|
54
|
+
# Class composition
|
55
|
+
#
|
56
|
+
element :country, 'Country', :tag => 'country'
|
57
|
+
|
58
|
+
attribute :occupied, Boolean
|
59
|
+
|
60
|
+
def initialize(parameters)
|
61
|
+
parameters.each_pair do |property,value|
|
62
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
63
|
+
end
|
64
|
+
@modified = @temporary = true
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Country is composed above the in Address class. Here is a demonstration
|
71
|
+
# of how to_xml will handle class composition as well as utilizing the tag
|
72
|
+
# value.
|
73
|
+
#
|
74
|
+
class Country
|
75
|
+
include HappyMapper
|
76
|
+
|
77
|
+
attribute :code, String, :tag => 'countryCode'
|
78
|
+
has_one :name, String, :tag => 'countryName'
|
79
|
+
has_one :description, 'Description', :tag => 'description'
|
80
|
+
|
81
|
+
#
|
82
|
+
# This inner-class here is to demonstrate saving a text node
|
83
|
+
# and optional attributes
|
84
|
+
#
|
85
|
+
class Description
|
86
|
+
include HappyMapper
|
87
|
+
content :description, String
|
88
|
+
attribute :category, String, :tag => 'category'
|
89
|
+
attribute :rating, String, :tag => 'rating', :state_when_nil => true
|
90
|
+
|
91
|
+
def initialize(desc)
|
92
|
+
@description = desc
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def initialize(parameters)
|
97
|
+
parameters.each_pair do |property,value|
|
98
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:subject) do
|
106
|
+
address = ToXML::Address.new 'street' => 'Mockingbird Lane',
|
107
|
+
'location' => 'Home',
|
108
|
+
'housenumber' => '1313',
|
109
|
+
'postcode' => '98103',
|
110
|
+
'city' => 'Seattle',
|
111
|
+
'country' => ToXML::Country.new(:name => 'USA', :code => 'us', :empty_code => nil,
|
112
|
+
:description => ToXML::Country::Description.new("A lovely country") ),
|
113
|
+
'date_created' => '2011-01-01 15:00:00',
|
114
|
+
'occupied' => false
|
115
|
+
|
116
|
+
address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
|
117
|
+
|
118
|
+
Nokogiri::XML(address.to_xml).root
|
119
|
+
end
|
120
|
+
|
121
|
+
it "saves elements" do
|
122
|
+
elements = { 'street' => 'Mockingbird Lane', 'postcode' => '98103', 'city' => 'Seattle' }
|
123
|
+
elements.each_pair do |property,value|
|
124
|
+
expect(subject.xpath("#{property}").text).to eq value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "saves attributes" do
|
129
|
+
expect(subject.xpath('@location').text).to eq "Home-live"
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'saves attributes that are Boolean and have a value of false' do
|
133
|
+
expect(subject.xpath('@occupied').text).to eq "false"
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when an element has a 'read_only' parameter" do
|
137
|
+
it "does not save elements" do
|
138
|
+
expect(subject.xpath('temporary')).to be_empty
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when an attribute has a 'read_only' parameter" do
|
143
|
+
it "does not save attributes" do
|
144
|
+
expect(subject.xpath("@modified")).to be_empty
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "when an element has a 'state_when_nil' parameter" do
|
149
|
+
it "saves an empty element" do
|
150
|
+
expect(subject.xpath('description').text).to eq ""
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "when an element has a 'on_save' parameter" do
|
155
|
+
context "with a symbol which represents a function" do
|
156
|
+
it "saves the element with the result of the function" do
|
157
|
+
expect(subject.xpath("housenumber").text).to eq "[1313]"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "with a lambda" do
|
162
|
+
it "saves the result of the lambda" do
|
163
|
+
expect(subject.xpath('date_created').text).to eq "15:00:00 01/01/11"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when a has_many has a 'on_save' parameter" do
|
169
|
+
context "with a lambda" do
|
170
|
+
it "saves the results" do
|
171
|
+
dates_updated = subject.xpath('dates_updated')
|
172
|
+
expect(dates_updated.length).to eq 2
|
173
|
+
expect(dates_updated.first.text).to eq "16:01:00 01/01/11"
|
174
|
+
expect(dates_updated.last.text).to eq "11:30:01 01/02/11"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context "when an attribute has a 'on_save' parameter" do
|
180
|
+
context "with a symbol which represents a function" do
|
181
|
+
it "saves the result" do
|
182
|
+
expect(subject.xpath('@location').text).to eq "Home-live"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "when an element type is a HappyMapper subclass" do
|
188
|
+
it "saves attributes" do
|
189
|
+
expect(subject.xpath('country/@countryCode').text).to eq "us"
|
190
|
+
end
|
191
|
+
|
192
|
+
it "saves elements" do
|
193
|
+
expect(subject.xpath('country/countryName').text).to eq "USA"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "saves elements" do
|
197
|
+
expect(subject.xpath('country/description').text).to eq "A lovely country"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|