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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +0 -3
  4. data/lib/happymapper/element.rb +2 -2
  5. data/lib/happymapper/supported_types.rb +3 -5
  6. data/lib/happymapper/version.rb +1 -1
  7. data/lib/happymapper.rb +44 -52
  8. metadata +98 -107
  9. data/spec/features/after_parse_callbacks_spec.rb +0 -32
  10. data/spec/features/attribute_default_value_spec.rb +0 -48
  11. data/spec/features/attributes_spec.rb +0 -35
  12. data/spec/features/has_many_empty_array_spec.rb +0 -44
  13. data/spec/features/ignay_spec.rb +0 -92
  14. data/spec/features/inheritance_spec.rb +0 -121
  15. data/spec/features/mixed_namespaces_spec.rb +0 -60
  16. data/spec/features/parse_with_object_to_update_spec.rb +0 -116
  17. data/spec/features/same_tag_different_meaning_spec.rb +0 -44
  18. data/spec/features/to_xml_spec.rb +0 -205
  19. data/spec/features/to_xml_with_namespaces_spec.rb +0 -237
  20. data/spec/features/wildcard_tag_name_spec.rb +0 -110
  21. data/spec/features/wrap_spec.rb +0 -87
  22. data/spec/features/xpath_spec.rb +0 -84
  23. data/spec/fixtures/address.xml +0 -9
  24. data/spec/fixtures/ambigous_items.xml +0 -22
  25. data/spec/fixtures/analytics.xml +0 -61
  26. data/spec/fixtures/analytics_profile.xml +0 -127
  27. data/spec/fixtures/atom.xml +0 -19
  28. data/spec/fixtures/commit.xml +0 -52
  29. data/spec/fixtures/current_weather.xml +0 -89
  30. data/spec/fixtures/current_weather_missing_elements.xml +0 -18
  31. data/spec/fixtures/default_namespace_combi.xml +0 -6
  32. data/spec/fixtures/dictionary.xml +0 -20
  33. data/spec/fixtures/family_tree.xml +0 -21
  34. data/spec/fixtures/inagy.xml +0 -85
  35. data/spec/fixtures/lastfm.xml +0 -355
  36. data/spec/fixtures/multiple_namespaces.xml +0 -170
  37. data/spec/fixtures/multiple_primitives.xml +0 -5
  38. data/spec/fixtures/optional_attributes.xml +0 -6
  39. data/spec/fixtures/pita.xml +0 -133
  40. data/spec/fixtures/posts.xml +0 -23
  41. data/spec/fixtures/product_default_namespace.xml +0 -18
  42. data/spec/fixtures/product_no_namespace.xml +0 -10
  43. data/spec/fixtures/product_single_namespace.xml +0 -10
  44. data/spec/fixtures/quarters.xml +0 -19
  45. data/spec/fixtures/radar.xml +0 -21
  46. data/spec/fixtures/set_config_options.xml +0 -3
  47. data/spec/fixtures/statuses.xml +0 -422
  48. data/spec/fixtures/subclass_namespace.xml +0 -50
  49. data/spec/fixtures/unformatted_address.xml +0 -1
  50. data/spec/fixtures/wrapper.xml +0 -11
  51. data/spec/happymapper/anonymous_mapper_spec.rb +0 -158
  52. data/spec/happymapper/attribute_spec.rb +0 -12
  53. data/spec/happymapper/item_spec.rb +0 -177
  54. data/spec/happymapper_spec.rb +0 -1208
  55. data/spec/spec_helper.rb +0 -25
@@ -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