nokogiri-happymapper 0.8.1 → 0.10.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 +30 -0
- data/README.md +1 -4
- data/lib/happymapper/anonymous_mapper.rb +6 -5
- data/lib/happymapper/class_methods.rb +466 -0
- data/lib/happymapper/element.rb +3 -3
- data/lib/happymapper/item.rb +19 -13
- data/lib/happymapper/supported_types.rb +4 -6
- data/lib/happymapper/syntax_error.rb +6 -0
- data/lib/happymapper/version.rb +1 -1
- data/lib/happymapper.rb +54 -505
- data/lib/nokogiri-happymapper.rb +1 -1
- metadata +100 -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
@@ -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
|
@@ -1,237 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
module ToXMLWithNamespaces
|
6
|
-
#
|
7
|
-
# Similar example as the to_xml but this time with namespacing
|
8
|
-
#
|
9
|
-
class Address
|
10
|
-
include HappyMapper
|
11
|
-
|
12
|
-
register_namespace 'address', 'http://www.company.com/address'
|
13
|
-
register_namespace 'country', 'http://www.company.com/country'
|
14
|
-
|
15
|
-
tag 'Address'
|
16
|
-
namespace 'address'
|
17
|
-
|
18
|
-
element :country, 'Country', tag: 'country', namespace: 'country'
|
19
|
-
|
20
|
-
attribute :location, String, on_save: :when_saving_location
|
21
|
-
|
22
|
-
element :street, String
|
23
|
-
element :postcode, String
|
24
|
-
element :city, String
|
25
|
-
|
26
|
-
element :housenumber, String
|
27
|
-
|
28
|
-
#
|
29
|
-
# to_xml will default to the attr_accessor method and not the attribute,
|
30
|
-
# allowing for that to be overwritten
|
31
|
-
#
|
32
|
-
undef :housenumber
|
33
|
-
def housenumber
|
34
|
-
"[#{@housenumber}]"
|
35
|
-
end
|
36
|
-
|
37
|
-
def when_saving_location(loc)
|
38
|
-
loc + '-live'
|
39
|
-
end
|
40
|
-
|
41
|
-
#
|
42
|
-
# Write a empty element even if this is not specified
|
43
|
-
#
|
44
|
-
element :description, String, state_when_nil: true
|
45
|
-
|
46
|
-
#
|
47
|
-
# Perform the on_save operation when saving
|
48
|
-
#
|
49
|
-
has_one :date_created, Time, on_save: ->(time) { Time.parse(time).strftime('%T %D') if time }
|
50
|
-
|
51
|
-
#
|
52
|
-
# Write multiple elements and call on_save when saving
|
53
|
-
#
|
54
|
-
has_many :dates_updated, Time, on_save: lambda { |times|
|
55
|
-
times.compact.map { |time| Time.parse(time).strftime('%T %D') } if times
|
56
|
-
}
|
57
|
-
|
58
|
-
#
|
59
|
-
# Class composition
|
60
|
-
#
|
61
|
-
|
62
|
-
def initialize(parameters)
|
63
|
-
parameters.each_pair do |property, value|
|
64
|
-
send("#{property}=", value) if respond_to?("#{property}=")
|
65
|
-
end
|
66
|
-
end
|
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
|
-
register_namespace 'countryName', 'http://www.company.com/countryName'
|
78
|
-
|
79
|
-
attribute :code, String, tag: 'countryCode'
|
80
|
-
has_one :name, String, tag: 'countryName', namespace: 'countryName'
|
81
|
-
|
82
|
-
def initialize(parameters)
|
83
|
-
parameters.each_pair do |property, value|
|
84
|
-
send("#{property}=", value) if respond_to?("#{property}=")
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
#
|
90
|
-
# This class is an example of a class that has a default namespace
|
91
|
-
# xmlns="urn:eventis:prodis:onlineapi:1.0"
|
92
|
-
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
93
|
-
# xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
94
|
-
#
|
95
|
-
class Recipe
|
96
|
-
include HappyMapper
|
97
|
-
|
98
|
-
# this is the default namespace of the document
|
99
|
-
register_namespace 'xmlns', 'urn:eventis:prodis:onlineapi:1.0'
|
100
|
-
register_namespace 'xsi', 'http://www.w3.org/2001/XMLSchema-instance'
|
101
|
-
register_namespace 'xsd', 'http://www.w3.org/2001/XMLSchema'
|
102
|
-
|
103
|
-
has_many :ingredients, String
|
104
|
-
|
105
|
-
def initialize(parameters)
|
106
|
-
parameters.each_pair { |property, value| send("#{property}=", value) if respond_to?("#{property}=") }
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
RSpec.describe 'Saving #to_xml with xml namespaces', type: :feature do
|
112
|
-
context 'with namespaces' do
|
113
|
-
let(:xml) do
|
114
|
-
country = ToXMLWithNamespaces::Country.new(name: 'USA', code: 'us')
|
115
|
-
address = ToXMLWithNamespaces::Address.new('street' => 'Mockingbird Lane',
|
116
|
-
'location' => 'Home',
|
117
|
-
'housenumber' => '1313',
|
118
|
-
'postcode' => '98103',
|
119
|
-
'city' => 'Seattle',
|
120
|
-
'country' => country,
|
121
|
-
'date_created' => '2011-01-01 15:00:00')
|
122
|
-
|
123
|
-
address.dates_updated = ['2011-01-01 16:01:00', '2011-01-02 11:30:01']
|
124
|
-
|
125
|
-
Nokogiri::XML(address.to_xml).root
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'sets the namespace specified in the class' do
|
129
|
-
expect(xml.xpath('/').children.first.namespace.prefix).to eq 'address'
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'saves elements' do
|
133
|
-
elements = { 'street' => 'Mockingbird Lane', 'postcode' => '98103', 'city' => 'Seattle' }
|
134
|
-
|
135
|
-
elements.each_pair do |property, value|
|
136
|
-
expect(xml.xpath("address:#{property}").text).to eq value
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
it 'saves attributes' do
|
141
|
-
expect(xml.xpath('@location').text).to eq 'Home-live'
|
142
|
-
end
|
143
|
-
|
144
|
-
context "when an element has a 'state_when_nil' parameter" do
|
145
|
-
it 'saves an empty element' do
|
146
|
-
expect(xml.xpath('address:description').text).to eq ''
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
context "when an element has a 'on_save' parameter" do
|
151
|
-
context 'with a symbol which represents a function' do
|
152
|
-
it 'saves the element with the result of a function call and not the value of the ivar' do
|
153
|
-
expect(xml.xpath('address:housenumber').text).to eq '[1313]'
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
context 'with a lambda' do
|
158
|
-
it 'saves the results' do
|
159
|
-
expect(xml.xpath('address:date_created').text).to eq '15:00:00 01/01/11'
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
context "when an attribute has a 'on_save' parameter" do
|
165
|
-
context 'with a lambda' do
|
166
|
-
it 'saves the result' do
|
167
|
-
expect(xml.xpath('@location').text).to eq 'Home-live'
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
context "when a has_many has a 'on_save' parameter" do
|
173
|
-
context 'with a lambda' do
|
174
|
-
it 'saves the result' do
|
175
|
-
dates_updated = xml.xpath('address:dates_updated')
|
176
|
-
|
177
|
-
aggregate_failures do
|
178
|
-
expect(dates_updated.length).to eq 2
|
179
|
-
expect(dates_updated.first.text).to eq '16:01:00 01/01/11'
|
180
|
-
expect(dates_updated.last.text).to eq '11:30:01 01/02/11'
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
context 'when an element type is a HappyMapper subclass' do
|
187
|
-
it 'saves attributes' do
|
188
|
-
expect(xml.xpath('country:country/@countryCode').text).to eq 'us'
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'saves elements' do
|
192
|
-
expect(xml.xpath('country:country/countryName:countryName').text).to eq 'USA'
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
context 'with a default namespace' do
|
198
|
-
it 'writes the default namespace to xml without repeating xmlns' do
|
199
|
-
recipe = ToXMLWithNamespaces::Recipe.new(ingredients: ['One Cup Flour', 'Two Scoops of Lovin'])
|
200
|
-
expect(recipe.to_xml).to match(/xmlns=\"urn:eventis:prodis:onlineapi:1\.0\"/)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
context 'namespace supplied by element declaration trumps namespace ' \
|
205
|
-
'specified by element class' do
|
206
|
-
|
207
|
-
let(:expected_xml) do
|
208
|
-
<<-XML.gsub(/^\s*\|/, '')
|
209
|
-
|<?xml version="1.0"?>
|
210
|
-
|<coffeemachine xmlns:beverage="http://beverages.org/Beverage/0.1" xmlns:coffee="http://coffee.org/Coffee/0.1">
|
211
|
-
| <beverage:beverage name="coffee"/>
|
212
|
-
|</coffeemachine>
|
213
|
-
XML
|
214
|
-
end
|
215
|
-
|
216
|
-
class Beverage
|
217
|
-
include HappyMapper
|
218
|
-
namespace 'coffee'
|
219
|
-
|
220
|
-
attribute :name, String
|
221
|
-
end
|
222
|
-
|
223
|
-
class CoffeeMachine
|
224
|
-
include HappyMapper
|
225
|
-
register_namespace 'coffee', 'http://coffee.org/Coffee/0.1'
|
226
|
-
register_namespace 'beverage', 'http://beverages.org/Beverage/0.1'
|
227
|
-
|
228
|
-
element :beverage, 'beverage', namespace: 'beverage'
|
229
|
-
end
|
230
|
-
|
231
|
-
it 'uses the element declaration namespace on the element' do
|
232
|
-
machine = CoffeeMachine.new
|
233
|
-
machine.beverage = Beverage.new.tap { |obj| obj.name = 'coffee' }
|
234
|
-
expect(machine.to_xml).to eq(expected_xml)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|