happymapper-swanandp 0.4.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 (41) hide show
  1. data/License +20 -0
  2. data/README.rdoc +55 -0
  3. data/Rakefile +35 -0
  4. data/examples/amazon.rb +34 -0
  5. data/examples/current_weather.rb +21 -0
  6. data/examples/dashed_elements.rb +20 -0
  7. data/examples/multi_street_address.rb +30 -0
  8. data/examples/post.rb +19 -0
  9. data/examples/twitter.rb +37 -0
  10. data/lib/happymapper.rb +321 -0
  11. data/lib/happymapper/attribute.rb +3 -0
  12. data/lib/happymapper/element.rb +3 -0
  13. data/lib/happymapper/item.rb +179 -0
  14. data/lib/happymapper/version.rb +3 -0
  15. data/spec/fixtures/address.xml +8 -0
  16. data/spec/fixtures/analytics.xml +61 -0
  17. data/spec/fixtures/commit.xml +52 -0
  18. data/spec/fixtures/current_weather.xml +89 -0
  19. data/spec/fixtures/family_tree.xml +7 -0
  20. data/spec/fixtures/multi_street_address.xml +9 -0
  21. data/spec/fixtures/multiple_namespaces.xml +170 -0
  22. data/spec/fixtures/nested_namespaces.xml +17 -0
  23. data/spec/fixtures/notes.xml +9 -0
  24. data/spec/fixtures/pita.xml +133 -0
  25. data/spec/fixtures/posts.xml +23 -0
  26. data/spec/fixtures/product_default_namespace.xml +10 -0
  27. data/spec/fixtures/product_no_namespace.xml +10 -0
  28. data/spec/fixtures/product_single_namespace.xml +10 -0
  29. data/spec/fixtures/radar.xml +21 -0
  30. data/spec/fixtures/raw.xml +9 -0
  31. data/spec/fixtures/statuses.xml +422 -0
  32. data/spec/happymapper_attribute_spec.rb +17 -0
  33. data/spec/happymapper_element_spec.rb +17 -0
  34. data/spec/happymapper_item_spec.rb +115 -0
  35. data/spec/happymapper_spec.rb +404 -0
  36. data/spec/happymapper_to_xml_namespaces_spec.rb +149 -0
  37. data/spec/happymapper_to_xml_spec.rb +138 -0
  38. data/spec/spec.opts +1 -0
  39. data/spec/spec_helper.rb +9 -0
  40. data/spec/support/models.rb +323 -0
  41. metadata +121 -0
@@ -0,0 +1,149 @@
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
+
20
+ attribute :location, String
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
+ def housenumber
33
+ "[#{@housenumber}]"
34
+ end
35
+
36
+ #
37
+ # Write a empty element even if this is not specified
38
+ #
39
+ element :description, String, :state_when_nil => true
40
+
41
+ #
42
+ # Perform the on_save operation when saving
43
+ #
44
+ has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
45
+
46
+ #
47
+ # Write multiple elements and call on_save when saving
48
+ #
49
+ has_many :dates_updated, Time, :on_save => lambda {|times|
50
+ times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
51
+
52
+ #
53
+ # Class composition
54
+ #
55
+
56
+ def initialize(parameters)
57
+ parameters.each_pair do |property,value|
58
+ send("#{property}=",value) if respond_to?("#{property}=")
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ #
65
+ # Country is composed above the in Address class. Here is a demonstration
66
+ # of how to_xml will handle class composition as well as utilizing the tag
67
+ # value.
68
+ #
69
+ class Country
70
+ include HappyMapper
71
+
72
+ register_namespace 'countryName', 'http://www.company.com/countryName'
73
+
74
+ attribute :code, String, :tag => 'countryCode'
75
+ has_one :name, String, :tag => 'countryName', :namespace => 'countryName'
76
+
77
+ def initialize(parameters)
78
+ parameters.each_pair do |property,value|
79
+ send("#{property}=",value) if respond_to?("#{property}=")
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ describe "#to_xml" do
86
+
87
+ context "Address" do
88
+
89
+ before(:all) do
90
+ address = Address.new('street' => 'Mockingbird Lane',
91
+ 'location' => 'Home',
92
+ 'housenumber' => '1313',
93
+ 'postcode' => '98103',
94
+ 'city' => 'Seattle',
95
+ 'country' => Country.new(:name => 'USA', :code => 'us'),
96
+ 'date_created' => '2011-01-01 15:00:00')
97
+
98
+ address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
99
+
100
+ @address_xml = XML::Parser.string(address.to_xml).parse.root
101
+ end
102
+
103
+ { 'street' => 'Mockingbird Lane',
104
+ 'postcode' => '98103',
105
+ 'city' => 'Seattle' }.each_pair do |property,value|
106
+
107
+ it "should have the element '#{property}' with the value '#{value}'" do
108
+ @address_xml.find("address:#{property}").first.child.to_s.should == value
109
+ end
110
+
111
+ end
112
+
113
+ it "should use the result of #housenumber method (not the @housenumber)" do
114
+ @address_xml.find("address:housenumber").first.child.to_s.should == "[1313]"
115
+ end
116
+
117
+ it "should have the attribute 'location' with the value 'Home'" do
118
+ @address_xml.find('@location').first.child.to_s.should == "Home"
119
+ end
120
+
121
+ it "should add an empty description element" do
122
+ @address_xml.find('address:description').first.child.to_s.should == ""
123
+ end
124
+
125
+ it "should call #on_save when saving the time to convert the time" do
126
+ @address_xml.find('address:date_created').first.child.to_s.should == "15:00:00 01/01/11"
127
+ end
128
+
129
+ it "should handle multiple elements for 'has_many'" do
130
+ dates_updated = @address_xml.find('address:dates_updated')
131
+ dates_updated.length.should == 2
132
+ dates_updated.first.child.to_s.should == "16:01:00 01/01/11"
133
+ dates_updated.last.child.to_s.should == "11:30:01 01/02/11"
134
+ end
135
+
136
+ it "should write the country code" do
137
+ @address_xml.find('country:country/@country:countryCode').first.child.to_s.should == "us"
138
+ end
139
+
140
+ it "should write the country name" do
141
+ @address_xml.find('country:country/countryName:countryName').first.child.to_s.should == "USA"
142
+ end
143
+
144
+ end
145
+
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ module ToXML
4
+
5
+ class Address
6
+ include HappyMapper
7
+
8
+ tag 'address'
9
+
10
+ attribute :location, String
11
+
12
+ element :street, String
13
+ element :postcode, String
14
+ element :city, String
15
+
16
+ element :housenumber, String
17
+
18
+ #
19
+ # to_xml will default to the attr_accessor method and not the attribute,
20
+ # allowing for that to be overwritten
21
+ #
22
+ def housenumber
23
+ "[#{@housenumber}]"
24
+ end
25
+
26
+ #
27
+ # Write a empty element even if this is not specified
28
+ #
29
+ element :description, String, :state_when_nil => true
30
+
31
+ #
32
+ # Perform the on_save operation when saving
33
+ #
34
+ has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
35
+
36
+ #
37
+ # Write multiple elements and call on_save when saving
38
+ #
39
+ has_many :dates_updated, Time, :on_save => lambda {|times|
40
+ times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
41
+
42
+ #
43
+ # Class composition
44
+ #
45
+ element :country, 'Country', :tag => 'country'
46
+
47
+ def initialize(parameters)
48
+ parameters.each_pair do |property,value|
49
+ send("#{property}=",value) if respond_to?("#{property}=")
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ #
56
+ # Country is composed above the in Address class. Here is a demonstration
57
+ # of how to_xml will handle class composition as well as utilizing the tag
58
+ # value.
59
+ #
60
+ class Country
61
+ include HappyMapper
62
+
63
+ attribute :code, String, :tag => 'countryCode'
64
+ has_one :name, String, :tag => 'countryName'
65
+
66
+ def initialize(parameters)
67
+ parameters.each_pair do |property,value|
68
+ send("#{property}=",value) if respond_to?("#{property}=")
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ describe "#to_xml" do
75
+
76
+ context "Address" do
77
+
78
+ before(:all) do
79
+ address = Address.new('street' => 'Mockingbird Lane',
80
+ 'location' => 'Home',
81
+ 'housenumber' => '1313',
82
+ 'postcode' => '98103',
83
+ 'city' => 'Seattle',
84
+ 'country' => Country.new(:name => 'USA', :code => 'us'),
85
+ 'date_created' => '2011-01-01 15:00:00')
86
+
87
+ address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
88
+
89
+ @address_xml = XML::Parser.string(address.to_xml).parse.root
90
+ end
91
+
92
+ { 'street' => 'Mockingbird Lane',
93
+ 'postcode' => '98103',
94
+ 'city' => 'Seattle' }.each_pair do |property,value|
95
+
96
+ it "should have the element '#{property}' with the value '#{value}'" do
97
+ @address_xml.find("#{property}").first.child.to_s.should == value
98
+ end
99
+
100
+ end
101
+
102
+ it "should use the result of #housenumber method (not the @housenumber)" do
103
+ @address_xml.find("housenumber").first.child.to_s.should == "[1313]"
104
+ end
105
+
106
+ it "should have the attribute 'location' with the value 'Home'" do
107
+ @address_xml.find('@location').first.child.to_s.should == "Home"
108
+ end
109
+
110
+ it "should add an empty description element" do
111
+ @address_xml.find('description').first.child.to_s.should == ""
112
+ end
113
+
114
+ it "should call #on_save when saving the time to convert the time" do
115
+ @address_xml.find('date_created').first.child.to_s.should == "15:00:00 01/01/11"
116
+ end
117
+
118
+ it "should handle multiple elements for 'has_many'" do
119
+ dates_updated = @address_xml.find('dates_updated')
120
+ dates_updated.length.should == 2
121
+ dates_updated.first.child.to_s.should == "16:01:00 01/01/11"
122
+ dates_updated.last.child.to_s.should == "11:30:01 01/02/11"
123
+ end
124
+
125
+ it "should write the country code" do
126
+ @address_xml.find('country/@countryCode').first.child.to_s.should == "us"
127
+ end
128
+
129
+ it "should write the country name" do
130
+ @address_xml.find('country/countryName').first.child.to_s.should == "USA"
131
+ end
132
+
133
+ end
134
+
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'spec'
5
+ require File.expand_path('../../lib/happymapper', __FILE__)
6
+
7
+ def fixture_file(filename)
8
+ File.read(File.dirname(__FILE__) + "/fixtures/#{filename}")
9
+ end
@@ -0,0 +1,323 @@
1
+ module Analytics
2
+ class Property
3
+ include HappyMapper
4
+
5
+ tag 'property'
6
+ namespace 'http://schemas.google.com/analytics/2009'
7
+ attribute :name, String
8
+ attribute :value, String
9
+ end
10
+
11
+ class Entry
12
+ include HappyMapper
13
+
14
+ tag 'entry'
15
+ element :id, String
16
+ element :updated, DateTime
17
+ element :title, String
18
+ element :table_id, String, :namespace => 'http://schemas.google.com/analytics/2009', :tag => 'tableId'
19
+ has_many :properties, Property
20
+ end
21
+
22
+ class Feed
23
+ include HappyMapper
24
+
25
+ tag 'feed'
26
+ element :id, String
27
+ element :updated, DateTime
28
+ element :title, String
29
+ has_many :entries, Entry
30
+ end
31
+ end
32
+
33
+ class Feature
34
+ include HappyMapper
35
+ element :name, String, :tag => '.|.//text()'
36
+ end
37
+
38
+ class FeatureBullet
39
+ include HappyMapper
40
+
41
+ tag 'features_bullets'
42
+ has_many :features, Feature
43
+ element :bug, String
44
+ end
45
+
46
+ class Product
47
+ include HappyMapper
48
+
49
+ element :title, String
50
+ has_one :feature_bullets, FeatureBullet
51
+ end
52
+
53
+ module FamilySearch
54
+ class Person
55
+ include HappyMapper
56
+
57
+ attribute :version, String
58
+ attribute :modified, Time
59
+ attribute :id, String
60
+ end
61
+
62
+ class Persons
63
+ include HappyMapper
64
+ has_many :person, Person
65
+ end
66
+
67
+ class FamilyTree
68
+ include HappyMapper
69
+
70
+ tag 'familytree'
71
+ attribute :version, String
72
+ attribute :status_message, String, :tag => 'statusMessage'
73
+ attribute :status_code, String, :tag => 'statusCode'
74
+ has_one :persons, Persons
75
+ end
76
+ end
77
+
78
+ module FedEx
79
+ class Address
80
+ include HappyMapper
81
+
82
+ tag 'Address'
83
+ namespace 'http://fedex.com/ws/track/v2'
84
+ element :city, String, :tag => 'City'
85
+ element :state, String, :tag => 'StateOrProvinceCode'
86
+ element :zip, String, :tag => 'PostalCode'
87
+ element :countrycode, String, :tag => 'CountryCode'
88
+ element :residential, Boolean, :tag => 'Residential'
89
+ end
90
+
91
+ class Event
92
+ include HappyMapper
93
+
94
+ tag 'Events'
95
+ namespace 'http://fedex.com/ws/track/v2'
96
+ element :timestamp, String, :tag => 'Timestamp'
97
+ element :eventtype, String, :tag => 'EventType'
98
+ element :eventdescription, String, :tag => 'EventDescription'
99
+ has_one :address, Address
100
+ end
101
+
102
+ class PackageWeight
103
+ include HappyMapper
104
+
105
+ tag 'PackageWeight'
106
+ namespace 'http://fedex.com/ws/track/v2'
107
+ element :units, String, :tag => 'Units'
108
+ element :value, Integer, :tag => 'Value'
109
+ end
110
+
111
+ class TrackDetails
112
+ include HappyMapper
113
+
114
+ tag 'TrackDetails'
115
+ namespace 'http://fedex.com/ws/track/v2'
116
+ element :tracking_number, String, :tag => 'TrackingNumber'
117
+ element :status_code, String, :tag => 'StatusCode'
118
+ element :status_desc, String, :tag => 'StatusDescription'
119
+ element :carrier_code, String, :tag => 'CarrierCode'
120
+ element :service_info, String, :tag => 'ServiceInfo'
121
+ has_one :weight, PackageWeight, :tag => 'PackageWeight'
122
+ element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
123
+ has_many :events, Event
124
+ end
125
+
126
+ class Notification
127
+ include HappyMapper
128
+
129
+ tag 'Notifications'
130
+ namespace 'http://fedex.com/ws/track/v2'
131
+ element :severity, String, :tag => 'Severity'
132
+ element :source, String, :tag => 'Source'
133
+ element :code, Integer, :tag => 'Code'
134
+ element :message, String, :tag => 'Message'
135
+ element :localized_message, String, :tag => 'LocalizedMessage'
136
+ end
137
+
138
+ class TransactionDetail
139
+ include HappyMapper
140
+
141
+ tag 'TransactionDetail'
142
+ namespace 'http://fedex.com/ws/track/v2'
143
+ element :cust_tran_id, String, :tag => 'CustomerTransactionId'
144
+ end
145
+
146
+ class TrackReply
147
+ include HappyMapper
148
+
149
+ tag 'TrackReply'
150
+ namespace 'http://fedex.com/ws/track/v2'
151
+ element :highest_severity, String, :tag => 'HighestSeverity'
152
+ element :more_data, Boolean, :tag => 'MoreData'
153
+ has_many :notifications, Notification, :tag => 'Notifications'
154
+ has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
155
+ has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
156
+ end
157
+ end
158
+
159
+ class Place
160
+ include HappyMapper
161
+ element :name, String
162
+ end
163
+
164
+ class Radar
165
+ include HappyMapper
166
+ has_many :places, Place
167
+ end
168
+
169
+ class Post
170
+ include HappyMapper
171
+
172
+ attribute :href, String
173
+ attribute :hash, String
174
+ attribute :description, String
175
+ attribute :tag, String
176
+ attribute :time, Time
177
+ attribute :others, Integer
178
+ attribute :extended, String
179
+ end
180
+
181
+ class User
182
+ include HappyMapper
183
+
184
+ element :id, Integer
185
+ element :name, String
186
+ element :screen_name, String
187
+ element :location, String
188
+ element :description, String
189
+ element :profile_image_url, String
190
+ element :url, String
191
+ element :protected, Boolean
192
+ element :followers_count, Integer
193
+
194
+ attr_accessor :after_parse_called
195
+ attr_accessor :after_parse2_called
196
+
197
+ after_parse do |doc|
198
+ doc.after_parse_called = true
199
+ end
200
+
201
+ after_parse do |doc|
202
+ doc.after_parse2_called = true
203
+ end
204
+ end
205
+
206
+ class Status
207
+ include HappyMapper
208
+
209
+ element :id, Integer
210
+ element :text, String
211
+ element :created_at, Time
212
+ element :source, String
213
+ element :truncated, Boolean
214
+ element :in_reply_to_status_id, Integer
215
+ element :in_reply_to_user_id, Integer
216
+ element :favorited, Boolean
217
+ element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
218
+ has_one :user, User
219
+ end
220
+
221
+ class CurrentWeather
222
+ include HappyMapper
223
+
224
+ tag 'ob'
225
+ namespace 'http://www.aws.com/aws'
226
+ element :temperature, Integer, :tag => 'temp'
227
+ element :feels_like, Integer, :tag => 'feels-like'
228
+ element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
229
+ end
230
+
231
+ class Address
232
+ include HappyMapper
233
+
234
+ tag 'address'
235
+ element :street, String
236
+ element :postcode, String
237
+ element :housenumber, String
238
+ element :city, String
239
+ element :country, String
240
+ end
241
+
242
+ class MultiStreetAddress
243
+ include HappyMapper
244
+
245
+ tag 'address'
246
+ # allow primitive type to be collection
247
+ has_many :street_address, String, :tag => "streetaddress"
248
+ element :city, String
249
+ element :state_or_providence, String, :tag => "stateOfProvidence"
250
+ element :zip, String
251
+ element :country, String
252
+ end
253
+
254
+ # for type coercion
255
+ class ProductGroup < String; end
256
+
257
+ module PITA
258
+ class Item
259
+ include HappyMapper
260
+
261
+ tag 'Item' # if you put class in module you need tag
262
+ element :asin, String, :tag => 'ASIN'
263
+ element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
264
+ element :manufacturer, String, :tag => 'Manufacturer', :deep => true
265
+ element :point, String, :tag => 'point', :namespace => 'http://www.georss.org/georss'
266
+ element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
267
+ end
268
+
269
+ class Items
270
+ include HappyMapper
271
+
272
+ tag 'Items' # if you put class in module you need tag
273
+ element :total_results, Integer, :tag => 'TotalResults'
274
+ element :total_pages, Integer, :tag => 'TotalPages'
275
+ has_many :items, Item
276
+ end
277
+ end
278
+
279
+ module GitHub
280
+ class Commit
281
+ include HappyMapper
282
+
283
+ tag "commit"
284
+ element :url, String
285
+ element :tree, String
286
+ element :message, String
287
+ element :id, String
288
+ element :'committed-date', Date
289
+ end
290
+ end
291
+
292
+ module Backpack
293
+ class Note
294
+ include HappyMapper
295
+
296
+ attribute :id, Integer
297
+ attribute :title, String
298
+ attribute :created_at, Date
299
+
300
+ content :body
301
+ end
302
+ end
303
+
304
+ module RawXml
305
+ class CustomStuff
306
+ include HappyMapper
307
+ raw_content :body
308
+ tag :custom
309
+ end
310
+
311
+ class Address
312
+ include HappyMapper
313
+
314
+ tag 'address'
315
+ element :street, String
316
+ element :postcode, String
317
+ element :housenumber, String
318
+ element :city, String
319
+ element :country, String
320
+ has_one :custom_stuff, RawXml::CustomStuff
321
+ end
322
+
323
+ end