nokogiri-happymapper 0.6.0 → 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 (60) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +64 -5
  3. data/README.md +296 -192
  4. data/lib/happymapper/anonymous_mapper.rb +46 -43
  5. data/lib/happymapper/attribute.rb +7 -5
  6. data/lib/happymapper/element.rb +19 -22
  7. data/lib/happymapper/item.rb +19 -21
  8. data/lib/happymapper/supported_types.rb +20 -28
  9. data/lib/happymapper/text_node.rb +4 -3
  10. data/lib/happymapper/version.rb +3 -1
  11. data/lib/happymapper.rb +336 -362
  12. data/lib/nokogiri-happymapper.rb +4 -0
  13. metadata +124 -105
  14. data/spec/attribute_default_value_spec.rb +0 -50
  15. data/spec/attributes_spec.rb +0 -36
  16. data/spec/fixtures/address.xml +0 -9
  17. data/spec/fixtures/ambigous_items.xml +0 -22
  18. data/spec/fixtures/analytics.xml +0 -61
  19. data/spec/fixtures/analytics_profile.xml +0 -127
  20. data/spec/fixtures/atom.xml +0 -19
  21. data/spec/fixtures/commit.xml +0 -52
  22. data/spec/fixtures/current_weather.xml +0 -89
  23. data/spec/fixtures/current_weather_missing_elements.xml +0 -18
  24. data/spec/fixtures/default_namespace_combi.xml +0 -6
  25. data/spec/fixtures/dictionary.xml +0 -20
  26. data/spec/fixtures/family_tree.xml +0 -21
  27. data/spec/fixtures/inagy.xml +0 -85
  28. data/spec/fixtures/lastfm.xml +0 -355
  29. data/spec/fixtures/multiple_namespaces.xml +0 -170
  30. data/spec/fixtures/multiple_primitives.xml +0 -5
  31. data/spec/fixtures/optional_attributes.xml +0 -6
  32. data/spec/fixtures/pita.xml +0 -133
  33. data/spec/fixtures/posts.xml +0 -23
  34. data/spec/fixtures/product_default_namespace.xml +0 -18
  35. data/spec/fixtures/product_no_namespace.xml +0 -10
  36. data/spec/fixtures/product_single_namespace.xml +0 -10
  37. data/spec/fixtures/quarters.xml +0 -19
  38. data/spec/fixtures/radar.xml +0 -21
  39. data/spec/fixtures/set_config_options.xml +0 -3
  40. data/spec/fixtures/statuses.xml +0 -422
  41. data/spec/fixtures/subclass_namespace.xml +0 -50
  42. data/spec/fixtures/unformatted_address.xml +0 -1
  43. data/spec/fixtures/wrapper.xml +0 -11
  44. data/spec/happymapper/attribute_spec.rb +0 -12
  45. data/spec/happymapper/element_spec.rb +0 -9
  46. data/spec/happymapper/item_spec.rb +0 -136
  47. data/spec/happymapper/text_node_spec.rb +0 -9
  48. data/spec/happymapper_parse_spec.rb +0 -113
  49. data/spec/happymapper_spec.rb +0 -1129
  50. data/spec/has_many_empty_array_spec.rb +0 -43
  51. data/spec/ignay_spec.rb +0 -95
  52. data/spec/inheritance_spec.rb +0 -107
  53. data/spec/mixed_namespaces_spec.rb +0 -61
  54. data/spec/parse_with_object_to_update_spec.rb +0 -111
  55. data/spec/spec_helper.rb +0 -7
  56. data/spec/to_xml_spec.rb +0 -201
  57. data/spec/to_xml_with_namespaces_spec.rb +0 -232
  58. data/spec/wilcard_tag_name_spec.rb +0 -96
  59. data/spec/wrap_spec.rb +0 -82
  60. data/spec/xpath_spec.rb +0 -89
@@ -1,232 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module ToXMLWithNamespaces
4
-
5
- #
6
- # Similar example as the to_xml but this time with namespacing
7
- #
8
- class Address
9
- include HappyMapper
10
-
11
- register_namespace 'address', 'http://www.company.com/address'
12
- register_namespace 'country', 'http://www.company.com/country'
13
-
14
- tag 'Address'
15
- namespace 'address'
16
-
17
- element :country, 'Country', :tag => 'country', :namespace => 'country'
18
-
19
- attribute :location, String, :on_save => :when_saving_location
20
-
21
- element :street, String
22
- element :postcode, String
23
- element :city, String
24
-
25
- element :housenumber, String
26
-
27
- #
28
- # to_xml will default to the attr_accessor method and not the attribute,
29
- # allowing for that to be overwritten
30
- #
31
- undef :housenumber
32
- def housenumber
33
- "[#{@housenumber}]"
34
- end
35
-
36
- def when_saving_location(loc)
37
- loc + '-live'
38
- end
39
-
40
- #
41
- # Write a empty element even if this is not specified
42
- #
43
- element :description, String, :state_when_nil => true
44
-
45
- #
46
- # Perform the on_save operation when saving
47
- #
48
- has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
49
-
50
- #
51
- # Write multiple elements and call on_save when saving
52
- #
53
- has_many :dates_updated, Time, :on_save => lambda {|times|
54
- times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
55
-
56
- #
57
- # Class composition
58
- #
59
-
60
- def initialize(parameters)
61
- parameters.each_pair do |property,value|
62
- send("#{property}=",value) if respond_to?("#{property}=")
63
- end
64
- end
65
-
66
- end
67
-
68
- #
69
- # Country is composed above the in Address class. Here is a demonstration
70
- # of how to_xml will handle class composition as well as utilizing the tag
71
- # value.
72
- #
73
- class Country
74
- include HappyMapper
75
-
76
- register_namespace 'countryName', 'http://www.company.com/countryName'
77
-
78
- attribute :code, String, :tag => 'countryCode'
79
- has_one :name, String, :tag => 'countryName', :namespace => 'countryName'
80
-
81
- def initialize(parameters)
82
- parameters.each_pair do |property,value|
83
- send("#{property}=",value) if respond_to?("#{property}=")
84
- end
85
- end
86
-
87
- end
88
-
89
-
90
- #
91
- # This class is an example of a class that has a default namespace
92
- #xmlns="urn:eventis:prodis:onlineapi:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
93
- #
94
- class Recipe
95
- include HappyMapper
96
-
97
- # this is the default namespace of the document
98
- register_namespace 'xmlns', 'urn:eventis:prodis:onlineapi:1.0'
99
- register_namespace 'xsi', "http://www.w3.org/2001/XMLSchema-instance"
100
- register_namespace 'xsd', "http://www.w3.org/2001/XMLSchema"
101
-
102
- has_many :ingredients, String
103
-
104
- def initialize(parameters)
105
- parameters.each_pair {|property,value| send("#{property}=",value) if respond_to?("#{property}=") }
106
- end
107
- end
108
- end
109
-
110
- describe "Saving #to_xml", "with xml namespaces" do
111
-
112
- context "#to_xml", "with namespaces" do
113
-
114
- let(:subject) do
115
- address = ToXMLWithNamespaces::Address.new('street' => 'Mockingbird Lane',
116
- 'location' => 'Home',
117
- 'housenumber' => '1313',
118
- 'postcode' => '98103',
119
- 'city' => 'Seattle',
120
- 'country' => ToXMLWithNamespaces::Country.new(:name => 'USA', :code => 'us'),
121
- 'date_created' => '2011-01-01 15:00:00')
122
-
123
-
124
- address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
125
-
126
- Nokogiri::XML(address.to_xml).root
127
- end
128
-
129
- it "saves elements" do
130
- elements = { 'street' => 'Mockingbird Lane', 'postcode' => '98103', 'city' => 'Seattle' }
131
-
132
- elements.each_pair do |property,value|
133
- expect(subject.xpath("address:#{property}").text).to eq value
134
- end
135
- end
136
-
137
- it "saves attributes" do
138
- expect(subject.xpath('@location').text).to eq "Home-live"
139
- end
140
-
141
- context "when an element has a 'state_when_nil' parameter" do
142
- it "saves an empty element" do
143
- expect(subject.xpath('address:description').text).to eq ""
144
- end
145
- end
146
-
147
- context "when an element has a 'on_save' parameter" do
148
- context "with a symbol which represents a function" do
149
- it "saves the element with the result of a function call and not the value of the instance variable" do
150
- expect(subject.xpath("address:housenumber").text).to eq "[1313]"
151
- end
152
- end
153
-
154
- context "with a lambda" do
155
- it "saves the results" do
156
- expect(subject.xpath('address:date_created').text).to eq "15:00:00 01/01/11"
157
- end
158
- end
159
- end
160
-
161
- context "when an attribute has a 'on_save' parameter" do
162
- context "with a lambda" do
163
- it "saves the result" do
164
- expect(subject.xpath('@location').text).to eq "Home-live"
165
- end
166
- end
167
- end
168
-
169
- context "when a has_many has a 'on_save' parameter" do
170
- context "with a lambda" do
171
- it "saves the result" do
172
- dates_updated = subject.xpath('address:dates_updated')
173
- expect(dates_updated.length).to eq 2
174
- expect(dates_updated.first.text).to eq "16:01:00 01/01/11"
175
- expect(dates_updated.last.text).to eq "11:30:01 01/02/11"
176
- end
177
- end
178
- end
179
-
180
- context "when an element type is a HappyMapper subclass" do
181
- it "saves attributes" do
182
- expect(subject.xpath('country:country/@countryCode').text).to eq "us"
183
- end
184
-
185
- it "saves elements" do
186
- expect(subject.xpath('country:country/countryName:countryName').text).to eq "USA"
187
- end
188
- end
189
- end
190
-
191
- context "with a default namespace" do
192
- it "writes the default namespace to xml without repeating xmlns" do
193
- recipe = ToXMLWithNamespaces::Recipe.new(:ingredients => ['One Cup Flour', 'Two Scoops of Lovin'])
194
- expect(recipe.to_xml).to match(/xmlns=\"urn:eventis:prodis:onlineapi:1\.0\"/)
195
- end
196
- end
197
-
198
- context 'namespace supplied by element declaration trumps namespace ' \
199
- 'specified by element class' do
200
-
201
- let(:expected_xml) do
202
- <<-XML.gsub(/^\s*\|/, '')
203
- |<?xml version="1.0"?>
204
- |<coffeemachine xmlns:coffee="http://coffee.org/Coffee/0.1" xmlns:beverage="http://beverages.org/Beverage/0.1">
205
- | <beverage:beverage name="coffee"/>
206
- |</coffeemachine>
207
- XML
208
- end
209
-
210
- class Beverage
211
- include HappyMapper
212
- namespace 'coffee'
213
-
214
- attribute :name, String
215
- end
216
-
217
- class CoffeeMachine
218
- include HappyMapper
219
- register_namespace 'coffee', "http://coffee.org/Coffee/0.1"
220
- register_namespace 'beverage', "http://beverages.org/Beverage/0.1"
221
-
222
- element :beverage, 'beverage', namespace: 'beverage'
223
- end
224
-
225
- it 'uses the element declaration namespace on the element' do
226
- machine = CoffeeMachine.new
227
- machine.beverage = Beverage.new.tap {|obj| obj.name = 'coffee'}
228
- expect(machine.to_xml).to eq(expected_xml)
229
- end
230
- end
231
-
232
- end
@@ -1,96 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Wildcard Root Tag" do
4
-
5
- generic_class_xml = %{
6
- <root>
7
- <description>some description</description>
8
- <blarg name='blargname1' href='http://blarg.com'/>
9
- <blarg name='blargname2' href='http://blarg.com'/>
10
- <jello name='jelloname' href='http://jello.com'/>
11
- <subelement>
12
- <jello name='subjelloname' href='http://ohnojello.com' other='othertext'/>
13
- </subelement>
14
- </root>}
15
-
16
- module GenericBase
17
- class Base
18
- include Comparable
19
- include HappyMapper
20
-
21
- def initialize(params = {})
22
- @name = params[:name]
23
- @href = params[:href]
24
- @other = params[:other]
25
- end
26
-
27
- tag '*'
28
- attribute :name, String
29
- attribute :href, String
30
- attribute :other, String
31
-
32
- def <=>(compared)
33
- name <=> compared.name && href <=> compared.href && other <=> compared.other
34
- end
35
- end
36
- class Sub
37
- include HappyMapper
38
- tag 'subelement'
39
- has_one :jello, Base, :tag => 'jello'
40
- end
41
- class Root
42
- include HappyMapper
43
- tag 'root'
44
- element :description, String
45
- has_many :blargs, Base, :tag => 'blarg', :xpath => '.'
46
- has_many :jellos, Base, :tag => 'jello', :xpath => '.'
47
- has_many :subjellos, Base, :tag => 'jello', :xpath => 'subelement/.', :read_only => true
48
- has_one :sub_element, Sub
49
- end
50
- end
51
-
52
- describe "can have generic classes using tag '*'" do
53
-
54
- let(:subject) { GenericBase::Root.parse(generic_class_xml) }
55
- let(:xml) { Nokogiri::XML(subject.to_xml) }
56
-
57
- it 'should map different elements to same class' do
58
- expect(subject.blargs).not_to be_nil
59
- expect(subject.jellos).not_to be_nil
60
- end
61
-
62
- it 'should filter on xpath appropriately' do
63
- expect(subject.blargs.size).to eq(2)
64
- expect(subject.jellos.size).to eq(1)
65
- expect(subject.subjellos.size).to eq(1)
66
- end
67
-
68
- def base_with(name,href,other)
69
- GenericBase::Base.new(:name => name,:href => href,:other => other)
70
- end
71
-
72
- it 'should parse correct values onto generic class' do
73
- expect(subject.blargs[0]).to eq base_with('blargname1','http://blarg.com',nil)
74
- expect(subject.blargs[1]).to eq base_with('blargname2','http://blarg.com',nil)
75
- expect(subject.jellos[0]).to eq base_with('jelloname','http://jello.com',nil)
76
- expect(subject.subjellos[0]).to eq base_with('subjelloname','http://ohnojello.com','othertext')
77
- end
78
-
79
- def validate_xpath(xpath,name,href,other)
80
- expect(xml.xpath("#{xpath}/@name").text).to eq name
81
- expect(xml.xpath("#{xpath}/@href").text).to eq href
82
- expect(xml.xpath("#{xpath}/@other").text).to eq other
83
- end
84
-
85
- it 'should #to_xml using parent element tag name' do
86
- expect(xml.xpath('/root/description').text).to eq('some description')
87
- validate_xpath("/root/blarg[1]","blargname1","http://blarg.com","")
88
- validate_xpath("/root/blarg[2]","blargname2","http://blarg.com","")
89
- validate_xpath("/root/jello[1]","jelloname","http://jello.com","")
90
- end
91
-
92
- it "should properly respect child HappyMapper tags if tag isn't provided on the element defintion" do
93
- expect(xml.xpath('root/subelement').size).to eq(1)
94
- end
95
- end
96
- end
data/spec/wrap_spec.rb DELETED
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "wrap which allows you to specify a wrapper element" do
4
-
5
- module Wrap
6
- class SubClass
7
- include HappyMapper
8
- tag 'subclass'
9
- attribute :myattr, String
10
- has_many :items, String, :tag => 'item'
11
- end
12
- class Root
13
- include HappyMapper
14
- tag 'root'
15
- attribute :attr1, String
16
- element :name, String
17
- wrap 'mywraptag' do
18
- element :description, String
19
- has_one :subclass, SubClass
20
- end
21
- element :number, Integer
22
- end
23
- end
24
-
25
- describe ".parse" do
26
- context "when given valid XML" do
27
- let(:subject) { Wrap::Root.parse fixture_file('wrapper.xml') }
28
-
29
- it 'sets the values correctly' do
30
- expect(subject.attr1).to eq 'somevalue'
31
- expect(subject.name).to eq 'myname'
32
- expect(subject.description).to eq 'some description'
33
- expect(subject.subclass.myattr).to eq 'attrvalue'
34
- expect(subject.subclass.items.size).to eq(2)
35
- expect(subject.subclass.items[0]).to eq 'item1'
36
- expect(subject.subclass.items[1]).to eq 'item2'
37
- expect(subject.number).to eq 12345
38
- end
39
- end
40
-
41
- context "when initialized without XML" do
42
- let(:subject) { Wrap::Root.new }
43
-
44
- it "anonymous classes are created so nil class values does not occur" do
45
- expect { subject.description = 'anything' }.to_not raise_error
46
- end
47
- end
48
- end
49
-
50
- describe ".to_xml" do
51
- let(:subject) do
52
- root = Wrap::Root.new
53
- root.attr1 = 'somevalue'
54
- root.name = 'myname'
55
- root.description = 'some description'
56
- root.number = 12345
57
-
58
- subclass = Wrap::SubClass.new
59
- subclass.myattr = 'attrvalue'
60
- subclass.items = []
61
- subclass.items << 'item1'
62
- subclass.items << 'item2'
63
-
64
- root.subclass = subclass
65
-
66
- root
67
- end
68
-
69
- it "generates the correct xml" do
70
- xml = Nokogiri::XML(subject.to_xml)
71
- expect(xml.xpath('/root/@attr1').text).to eq 'somevalue'
72
- expect(xml.xpath('/root/name').text).to eq 'myname'
73
- expect(xml.xpath('/root/mywraptag/description').text).to eq 'some description'
74
- expect(xml.xpath('/root/mywraptag/subclass/@myattr').text).to eq 'attrvalue'
75
- expect(xml.xpath('/root/mywraptag/subclass/item').size).to eq(2)
76
- expect(xml.xpath('/root/mywraptag/subclass/item[1]').text).to eq 'item1'
77
- expect(xml.xpath('/root/mywraptag/subclass/item[2]').text).to eq 'item2'
78
- expect(xml.xpath('/root/number').text).to eq '12345'
79
- end
80
-
81
- end
82
- end
data/spec/xpath_spec.rb DELETED
@@ -1,89 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Specifying elements and attributes with an xpath" do
4
-
5
- class Item
6
- include HappyMapper
7
-
8
- tag 'item'
9
- namespace 'amazing'
10
-
11
- element :title, String
12
- attribute :link, String, :xpath => 'amazing:link/@href'
13
- has_one :different_link, String, :xpath => 'different:link/@href'
14
- element :detail, String, :xpath => 'amazing:subitem/amazing:detail'
15
- has_many :more_details_text, String, :xpath => 'amazing:subitem/amazing:more'
16
- has_many :more_details, String, :xpath => 'amazing:subitem/amazing:more/@first|amazing:subitem/amazing:more/@alternative'
17
- has_many :more_details_alternative, String, :xpath => 'amazing:subitem/amazing:more/@*'
18
-
19
- has_one :baby, 'Baby', :name => 'baby', :namespace => 'amazing'
20
-
21
- end
22
-
23
- class Baby
24
- include HappyMapper
25
-
26
- has_one :name, String
27
- end
28
-
29
- let(:subject) { Item.parse(xml_string,:single => true) }
30
-
31
- let(:xml_string) do
32
- %{
33
- <rss>
34
- <amazing:item xmlns:amazing="http://www.amazing.com/amazing" xmlns:different="http://www.different.com/different">
35
- <amazing:title>Test XML</amazing:title>
36
- <different:link href="different_link" />
37
- <amazing:link href="link_to_resources" />
38
- <amazing:subitem>
39
- <amazing:detail>I want to parse this</amazing:detail>
40
- <amazing:more first="this one">more 1</amazing:more>
41
- <amazing:more alternative="another one">more 2</amazing:more>
42
- </amazing:subitem>
43
- <amazing:baby>
44
- <amazing:name>Jumbo</amazing:name>
45
- </amazing:baby>
46
- </amazing:item>
47
- </rss>
48
- }
49
- end
50
-
51
- it "should have a title" do
52
- expect(subject.title).to eq "Test XML"
53
- end
54
-
55
- it "should find the link href value" do
56
- expect(subject.link).to eq 'link_to_resources'
57
- end
58
-
59
- it "should find the link href value" do
60
- expect(subject.different_link).to eq 'different_link'
61
- end
62
-
63
- it "should find this subitem based on the xpath" do
64
- expect(subject.detail).to eq 'I want to parse this'
65
- end
66
-
67
- it "should find the subitems based on the xpath" do
68
- expect(subject.more_details_text.size).to eq(2)
69
- expect(subject.more_details_text.first).to eq "more 1"
70
- expect(subject.more_details_text.last).to eq "more 2"
71
- end
72
-
73
- it "should find the subitems based on the xpath" do
74
- expect(subject.more_details.size).to eq(2)
75
- expect(subject.more_details.first).to eq "this one"
76
- expect(subject.more_details.last).to eq "another one"
77
- end
78
-
79
- it "should find the subitems based on the xpath" do
80
- expect(subject.more_details_alternative.size).to eq(2)
81
- expect(subject.more_details_alternative.first).to eq "this one"
82
- expect(subject.more_details_alternative.last).to eq "another one"
83
- end
84
-
85
- it "should have a baby name" do
86
- expect(subject.baby.name).to eq "Jumbo"
87
- end
88
-
89
- end