nokogiri-happymapper 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|