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