legolin-happymapper 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/HOW_TO_RELEASE +5 -0
  2. data/History +59 -0
  3. data/License +20 -0
  4. data/Manifest +42 -0
  5. data/README +61 -0
  6. data/Rakefile +43 -0
  7. data/TODO +0 -0
  8. data/examples/amazon.rb +34 -0
  9. data/examples/current_weather.rb +21 -0
  10. data/examples/dashed_elements.rb +20 -0
  11. data/examples/multi_street_address.rb +15 -0
  12. data/examples/post.rb +19 -0
  13. data/examples/twitter.rb +37 -0
  14. data/happymapper.gemspec +0 -0
  15. data/legolin-happymapper.gemspec +34 -0
  16. data/lib/happymapper.rb +161 -0
  17. data/lib/happymapper/attribute.rb +3 -0
  18. data/lib/happymapper/element.rb +3 -0
  19. data/lib/happymapper/item.rb +192 -0
  20. data/lib/happymapper/version.rb +3 -0
  21. data/spec/fixtures/address.xml +8 -0
  22. data/spec/fixtures/analytics.xml +61 -0
  23. data/spec/fixtures/commit.xml +52 -0
  24. data/spec/fixtures/current_weather.xml +89 -0
  25. data/spec/fixtures/family_tree.xml +7 -0
  26. data/spec/fixtures/multi_street_address.xml +9 -0
  27. data/spec/fixtures/multiple_namespaces.xml +170 -0
  28. data/spec/fixtures/nested_namespaces.xml +17 -0
  29. data/spec/fixtures/pita.xml +133 -0
  30. data/spec/fixtures/posts.xml +23 -0
  31. data/spec/fixtures/product_default_namespace.xml +10 -0
  32. data/spec/fixtures/product_no_namespace.xml +10 -0
  33. data/spec/fixtures/product_single_namespace.xml +10 -0
  34. data/spec/fixtures/radar.xml +21 -0
  35. data/spec/fixtures/statuses.xml +422 -0
  36. data/spec/happymapper_attribute_spec.rb +17 -0
  37. data/spec/happymapper_element_spec.rb +17 -0
  38. data/spec/happymapper_item_spec.rb +115 -0
  39. data/spec/happymapper_spec.rb +719 -0
  40. data/spec/spec.opts +1 -0
  41. data/spec/spec_helper.rb +13 -0
  42. data/website/css/common.css +47 -0
  43. data/website/index.html +98 -0
  44. metadata +129 -0
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HappyMapper::Attribute do
4
+ describe "initialization" do
5
+ before do
6
+ @attr = HappyMapper::Attribute.new(:foo, String)
7
+ end
8
+
9
+ it 'should know that it is an attribute' do
10
+ @attr.attribute?.should be_true
11
+ end
12
+
13
+ it 'should know that it is NOT an element' do
14
+ @attr.element?.should be_false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HappyMapper::Element do
4
+ describe "initialization" do
5
+ before do
6
+ @attr = HappyMapper::Element.new(:foo, String)
7
+ end
8
+
9
+ it 'should know that it is an element' do
10
+ @attr.element?.should be_true
11
+ end
12
+
13
+ it 'should know that it is NOT an attribute' do
14
+ @attr.attribute?.should be_false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,115 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ module Foo
4
+ class Bar; end
5
+ end
6
+
7
+ describe HappyMapper::Item do
8
+
9
+ describe "new instance" do
10
+ before do
11
+ @item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
12
+ end
13
+
14
+ it "should accept a name" do
15
+ @item.name.should == 'foo'
16
+ end
17
+
18
+ it 'should accept a type' do
19
+ @item.type.should == String
20
+ end
21
+
22
+ it 'should accept :tag as an option' do
23
+ @item.tag.should == 'foobar'
24
+ end
25
+
26
+ it "should have a method_name" do
27
+ @item.method_name.should == 'foo'
28
+ end
29
+ end
30
+
31
+ describe "#constant" do
32
+ it "should just use type if constant" do
33
+ item = HappyMapper::Item.new(:foo, String)
34
+ item.constant.should == String
35
+ end
36
+
37
+ it "should convert string type to constant" do
38
+ item = HappyMapper::Item.new(:foo, 'String')
39
+ item.constant.should == String
40
+ end
41
+
42
+ it "should convert string with :: to constant" do
43
+ item = HappyMapper::Item.new(:foo, 'Foo::Bar')
44
+ item.constant.should == Foo::Bar
45
+ end
46
+ end
47
+
48
+ describe "#method_name" do
49
+ it "should convert dashes to underscores" do
50
+ item = HappyMapper::Item.new(:'foo-bar', String, :tag => 'foobar')
51
+ item.method_name.should == 'foo_bar'
52
+ end
53
+ end
54
+
55
+ describe "#xpath" do
56
+ it "should default to tag" do
57
+ item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
58
+ item.xpath.should == 'foobar'
59
+ end
60
+
61
+ it "should prepend with .// if options[:deep] true" do
62
+ item = HappyMapper::Item.new(:foo, String, :tag => 'foobar', :deep => true)
63
+ item.xpath.should == './/foobar'
64
+ end
65
+
66
+ it "should prepend namespace if namespace exists" do
67
+ item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
68
+ item.namespace = 'http://example.com'
69
+ item.xpath.should == 'happymapper:foobar'
70
+ end
71
+ end
72
+
73
+ describe "typecasting" do
74
+ it "should work with Strings" do
75
+ item = HappyMapper::Item.new(:foo, String)
76
+ [21, '21'].each do |a|
77
+ item.typecast(a).should == '21'
78
+ end
79
+ end
80
+
81
+ it "should work with Integers" do
82
+ item = HappyMapper::Item.new(:foo, Integer)
83
+ [21, 21.0, '21'].each do |a|
84
+ item.typecast(a).should == 21
85
+ end
86
+ end
87
+
88
+ it "should work with Floats" do
89
+ item = HappyMapper::Item.new(:foo, Float)
90
+ [21, 21.0, '21'].each do |a|
91
+ item.typecast(a).should == 21.0
92
+ end
93
+ end
94
+
95
+ it "should work with Times" do
96
+ item = HappyMapper::Item.new(:foo, Time)
97
+ item.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
98
+ end
99
+
100
+ it "should work with Dates" do
101
+ item = HappyMapper::Item.new(:foo, Date)
102
+ item.typecast('2000-01-01').should == Date.new(2000, 1, 1)
103
+ end
104
+
105
+ it "should work with DateTimes" do
106
+ item = HappyMapper::Item.new(:foo, DateTime)
107
+ item.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
108
+ end
109
+
110
+ it "should work with Boolean" do
111
+ item = HappyMapper::Item.new(:foo, Boolean)
112
+ item.typecast('false').should == false
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,719 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require 'pp'
3
+ require 'uri'
4
+
5
+ module Analytics
6
+ class Property
7
+ include HappyMapper
8
+
9
+ tag 'property'
10
+ namespace 'http://schemas.google.com/analytics/2009'
11
+ attribute :name, String
12
+ attribute :value, String
13
+ end
14
+
15
+ class Entry
16
+ include HappyMapper
17
+
18
+ tag 'entry'
19
+ element :id, String
20
+ element :updated, DateTime
21
+ element :title, String
22
+ element :table_id, String, :namespace => 'http://schemas.google.com/analytics/2009', :tag => 'tableId'
23
+ has_many :properties, Property
24
+ end
25
+
26
+ class Feed
27
+ include HappyMapper
28
+
29
+ tag 'feed'
30
+ element :id, String
31
+ element :updated, DateTime
32
+ element :title, String
33
+ has_many :entries, Entry
34
+ end
35
+ end
36
+
37
+ class Feature
38
+ include HappyMapper
39
+ element :name, String, :tag => '.|.//text()'
40
+ end
41
+
42
+ class FeatureBullet
43
+ include HappyMapper
44
+
45
+ tag 'features_bullets'
46
+ has_many :features, Feature
47
+ element :bug, String
48
+ end
49
+
50
+ class Product
51
+ include HappyMapper
52
+
53
+ element :title, String
54
+ has_one :feature_bullets, FeatureBullet
55
+ end
56
+
57
+ module FamilySearch
58
+ class Person
59
+ include HappyMapper
60
+
61
+ attribute :version, String
62
+ attribute :modified, Time
63
+ attribute :id, String
64
+ end
65
+
66
+ class Persons
67
+ include HappyMapper
68
+ has_many :person, Person
69
+ end
70
+
71
+ class FamilyTree
72
+ include HappyMapper
73
+
74
+ tag 'familytree'
75
+ attribute :version, String
76
+ attribute :status_message, String, :tag => 'statusMessage'
77
+ attribute :status_code, String, :tag => 'statusCode'
78
+ has_one :persons, Persons
79
+ end
80
+ end
81
+
82
+ module FedEx
83
+ class Address
84
+ include HappyMapper
85
+
86
+ tag 'Address'
87
+ namespace 'http://fedex.com/ws/track/v2'
88
+ element :city, String, :tag => 'City'
89
+ element :state, String, :tag => 'StateOrProvinceCode'
90
+ element :zip, String, :tag => 'PostalCode'
91
+ element :countrycode, String, :tag => 'CountryCode'
92
+ element :residential, Boolean, :tag => 'Residential'
93
+ end
94
+
95
+ class Event
96
+ include HappyMapper
97
+
98
+ tag 'Events'
99
+ namespace 'http://fedex.com/ws/track/v2'
100
+ element :timestamp, String, :tag => 'Timestamp'
101
+ element :eventtype, String, :tag => 'EventType'
102
+ element :eventdescription, String, :tag => 'EventDescription'
103
+ has_one :address, Address
104
+ end
105
+
106
+ class PackageWeight
107
+ include HappyMapper
108
+
109
+ tag 'PackageWeight'
110
+ namespace 'http://fedex.com/ws/track/v2'
111
+ element :units, String, :tag => 'Units'
112
+ element :value, Integer, :tag => 'Value'
113
+ end
114
+
115
+ class TrackDetails
116
+ include HappyMapper
117
+
118
+ tag 'TrackDetails'
119
+ namespace 'http://fedex.com/ws/track/v2'
120
+ element :tracking_number, String, :tag => 'TrackingNumber'
121
+ element :status_code, String, :tag => 'StatusCode'
122
+ element :status_desc, String, :tag => 'StatusDescription'
123
+ element :carrier_code, String, :tag => 'CarrierCode'
124
+ element :service_info, String, :tag => 'ServiceInfo'
125
+ has_one :weight, PackageWeight, :tag => 'PackageWeight'
126
+ element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
127
+ has_many :events, Event
128
+ end
129
+
130
+ class Notification
131
+ include HappyMapper
132
+
133
+ tag 'Notifications'
134
+ namespace 'http://fedex.com/ws/track/v2'
135
+ element :severity, String, :tag => 'Severity'
136
+ element :source, String, :tag => 'Source'
137
+ element :code, Integer, :tag => 'Code'
138
+ element :message, String, :tag => 'Message'
139
+ element :localized_message, String, :tag => 'LocalizedMessage'
140
+ end
141
+
142
+ class TransactionDetail
143
+ include HappyMapper
144
+
145
+ tag 'TransactionDetail'
146
+ namespace 'http://fedex.com/ws/track/v2'
147
+ element :cust_tran_id, String, :tag => 'CustomerTransactionId'
148
+ end
149
+
150
+ class TrackReply
151
+ include HappyMapper
152
+
153
+ tag 'TrackReply'
154
+ namespace 'http://fedex.com/ws/track/v2'
155
+ element :highest_severity, String, :tag => 'HighestSeverity'
156
+ element :more_data, Boolean, :tag => 'MoreData'
157
+ has_many :notifications, Notification, :tag => 'Notifications'
158
+ has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
159
+ has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
160
+ end
161
+ end
162
+
163
+ class Place
164
+ include HappyMapper
165
+ element :name, String
166
+ end
167
+
168
+ class Radar
169
+ include HappyMapper
170
+ has_many :places, Place
171
+ end
172
+
173
+ class Post
174
+ include HappyMapper
175
+
176
+ attribute :href, String
177
+ attribute :hash, String
178
+ attribute :description, String
179
+ attribute :tag, String
180
+ attribute :time, Time
181
+ attribute :others, Integer
182
+ attribute :extended, String
183
+ end
184
+
185
+ class User
186
+ include HappyMapper
187
+
188
+ element :id, Integer
189
+ element :name, String
190
+ element :screen_name, String
191
+ element :location, String
192
+ element :description, String
193
+ element :profile_image_url, String
194
+ element :url, String
195
+ element :protected, Boolean
196
+ element :followers_count, Integer
197
+ end
198
+
199
+ class Status
200
+ include HappyMapper
201
+
202
+ element :id, Integer
203
+ element :text, String
204
+ element :created_at, Time
205
+ element :source, String
206
+ element :truncated, Boolean
207
+ element :in_reply_to_status_id, Integer
208
+ element :in_reply_to_user_id, Integer
209
+ element :favorited, Boolean
210
+ element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
211
+ has_one :user, User
212
+ end
213
+
214
+ class CurrentWeather
215
+ include HappyMapper
216
+
217
+ tag 'ob'
218
+ namespace 'http://www.aws.com/aws'
219
+ element :temperature, Integer, :tag => 'temp'
220
+ element :feels_like, Integer, :tag => 'feels-like'
221
+ element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
222
+ end
223
+
224
+ class Address
225
+ include HappyMapper
226
+
227
+ tag 'address'
228
+ element :street, String
229
+ element :postcode, String
230
+ element :housenumber, String
231
+ element :city, String
232
+ element :country, String
233
+ end
234
+
235
+ # for type coercion
236
+ class ProductGroup < String; end
237
+
238
+ module PITA
239
+ class Item
240
+ include HappyMapper
241
+
242
+ tag 'Item' # if you put class in module you need tag
243
+ element :asin, String, :tag => 'ASIN'
244
+ element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
245
+ element :manufacturer, String, :tag => 'Manufacturer', :deep => true
246
+ element :point, String, :tag => 'point', :namespace => 'http://www.georss.org/georss'
247
+ element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
248
+ end
249
+
250
+ class Items
251
+ include HappyMapper
252
+
253
+ tag 'Items' # if you put class in module you need tag
254
+ element :total_results, Integer, :tag => 'TotalResults'
255
+ element :total_pages, Integer, :tag => 'TotalPages'
256
+ has_many :items, Item
257
+ end
258
+ end
259
+
260
+ module GitHub
261
+ class Commit
262
+ include HappyMapper
263
+
264
+ tag "commit"
265
+ element :url, String
266
+ element :tree, String
267
+ element :message, String
268
+ element :id, String
269
+ element :'committed-date', Date
270
+ end
271
+ end
272
+
273
+ module Groups
274
+ class GroupElement
275
+ include HappyMapper
276
+
277
+ attribute :id, String
278
+ end
279
+
280
+ class Group
281
+ include HappyMapper
282
+
283
+ has_many :GroupElements, GroupElement, :group_tag => "groupelements"
284
+ end
285
+ end
286
+
287
+
288
+ describe HappyMapper do
289
+
290
+ describe "being included into another class" do
291
+ before do
292
+ @klass = Class.new do
293
+ include HappyMapper
294
+
295
+ def self.to_s
296
+ 'Foo'
297
+ end
298
+ end
299
+ end
300
+
301
+ it "should set attributes to an array" do
302
+ @klass.attributes.should == []
303
+ end
304
+
305
+ it "should set @elements to a hash" do
306
+ @klass.elements.should == []
307
+ end
308
+
309
+ it "should allow adding an attribute" do
310
+ lambda {
311
+ @klass.attribute :name, String
312
+ }.should change(@klass, :attributes)
313
+ end
314
+
315
+ it "should allow adding an attribute containing a dash" do
316
+ lambda {
317
+ @klass.attribute :'bar-baz', String
318
+ }.should change(@klass, :attributes)
319
+ end
320
+
321
+ it "should be able to get all attributes in array" do
322
+ @klass.attribute :name, String
323
+ @klass.attributes.size.should == 1
324
+ end
325
+
326
+ it "should allow adding an element" do
327
+ lambda {
328
+ @klass.element :name, String
329
+ }.should change(@klass, :elements)
330
+ end
331
+
332
+ it "should allow adding an element containing a dash" do
333
+ lambda {
334
+ @klass.element :'bar-baz', String
335
+ }.should change(@klass, :elements)
336
+
337
+ end
338
+
339
+ it "should be able to get all elements in array" do
340
+ @klass.element(:name, String)
341
+ @klass.elements.size.should == 1
342
+ end
343
+
344
+ it "should allow has one association" do
345
+ @klass.has_one(:user, User)
346
+ element = @klass.elements.first
347
+ element.name.should == 'user'
348
+ element.type.should == User
349
+ element.options[:single] = true
350
+ end
351
+
352
+ it "should allow has many association" do
353
+ @klass.has_many(:users, User)
354
+ element = @klass.elements.first
355
+ element.name.should == 'users'
356
+ element.type.should == User
357
+ element.options[:single] = false
358
+ end
359
+
360
+ it "should default tag name to lowercase class" do
361
+ @klass.tag_name.should == 'foo'
362
+ end
363
+
364
+ it "should default tag name of class in modules to the last constant lowercase" do
365
+ module Bar; class Baz; include HappyMapper; end; end
366
+ Bar::Baz.tag_name.should == 'baz'
367
+ end
368
+
369
+ it "should allow setting tag name" do
370
+ @klass.tag('FooBar')
371
+ @klass.tag_name.should == 'FooBar'
372
+ end
373
+
374
+ it "should allow setting a namespace" do
375
+ @klass.namespace(namespace = "foo")
376
+ @klass.namespace.should == namespace
377
+ end
378
+
379
+ it "should provide #parse" do
380
+ @klass.should respond_to(:parse)
381
+ end
382
+ end
383
+
384
+ describe "#attributes" do
385
+ it "should only return attributes for the current class" do
386
+ Post.attributes.size.should == 7
387
+ Status.attributes.size.should == 0
388
+ end
389
+ end
390
+
391
+ describe "#elements" do
392
+ it "should only return elements for the current class" do
393
+ Post.elements.size.should == 0
394
+ Status.elements.size.should == 10
395
+ end
396
+ end
397
+
398
+ it "should parse xml attributes into ruby objects" do
399
+ posts = Post.parse(fixture_file('posts.xml'))
400
+ posts.size.should == 20
401
+ first = posts.first
402
+ first.href.should == 'http://roxml.rubyforge.org/'
403
+ first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
404
+ first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
405
+ first.tag.should == 'ruby xml gems mapping'
406
+ first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
407
+ first.others.should == 56
408
+ first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.'
409
+ end
410
+
411
+ it "should parse xml elements to ruby objcts" do
412
+ statuses = Status.parse(fixture_file('statuses.xml'))
413
+ statuses.size.should == 20
414
+ first = statuses.first
415
+ first.id.should == 882281424
416
+ first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12)
417
+ first.source.should == 'web'
418
+ first.truncated.should be_false
419
+ first.in_reply_to_status_id.should == 1234
420
+ first.in_reply_to_user_id.should == 12345
421
+ first.favorited.should be_false
422
+ first.user.id.should == 4243
423
+ first.user.name.should == 'John Nunemaker'
424
+ first.user.screen_name.should == 'jnunemaker'
425
+ first.user.location.should == 'Mishawaka, IN, US'
426
+ first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
427
+ first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
428
+ first.user.url.should == 'http://addictedtonew.com'
429
+ first.user.protected.should be_false
430
+ first.user.followers_count.should == 486
431
+ end
432
+
433
+ it "should parse xml containing the desired element as root node" do
434
+ address = Address.parse(fixture_file('address.xml'), :single => true)
435
+ address.street.should == 'Milchstrasse'
436
+ address.postcode.should == '26131'
437
+ address.housenumber.should == '23'
438
+ address.city.should == 'Oldenburg'
439
+ address.country.should == 'Germany'
440
+ end
441
+
442
+ it "should parse xml with default namespace (amazon)" do
443
+ file_contents = fixture_file('pita.xml')
444
+ items = PITA::Items.parse(file_contents, :single => true)
445
+ items.total_results.should == 22
446
+ items.total_pages.should == 3
447
+ first = items.items[0]
448
+ second = items.items[1]
449
+ first.asin.should == '0321480791'
450
+ first.point.should == '38.5351715088 -121.7948684692'
451
+ first.detail_page_url.should be_a_kind_of(URI)
452
+ first.detail_page_url.to_s.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
453
+ first.manufacturer.should == 'Addison-Wesley Professional'
454
+ first.product_group.should == '<ProductGroup>Book</ProductGroup>'
455
+ second.asin.should == '047022388X'
456
+ second.manufacturer.should == 'Wrox'
457
+ end
458
+
459
+ it "should parse xml that has attributes of elements" do
460
+ items = CurrentWeather.parse(fixture_file('current_weather.xml'))
461
+ first = items[0]
462
+ first.temperature.should == 51
463
+ first.feels_like.should == 51
464
+ first.current_condition.should == 'Sunny'
465
+ first.current_condition.icon.should == 'http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif'
466
+ end
467
+
468
+ it "should parse xml with nested elements" do
469
+ radars = Radar.parse(fixture_file('radar.xml'))
470
+ first = radars[0]
471
+ first.places.size.should == 1
472
+ first.places[0].name.should == 'Store'
473
+ second = radars[1]
474
+ second.places.size.should == 0
475
+ third = radars[2]
476
+ third.places.size.should == 2
477
+ third.places[0].name.should == 'Work'
478
+ third.places[1].name.should == 'Home'
479
+ end
480
+
481
+ it "should parse xml that has elements with dashes" do
482
+ commit = GitHub::Commit.parse(fixture_file('commit.xml'))
483
+ commit.message.should == "move commands.rb and helpers.rb into commands/ dir"
484
+ commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
485
+ commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
486
+ commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00")
487
+ commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76"
488
+ end
489
+
490
+ it "should parse xml with no namespace" do
491
+ product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true)
492
+ product.title.should == "A Title"
493
+ product.feature_bullets.bug.should == 'This is a bug'
494
+ product.feature_bullets.features.size.should == 2
495
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
496
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
497
+ end
498
+
499
+ it "should parse xml with default namespace" do
500
+ product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
501
+ product.title.should == "A Title"
502
+ product.feature_bullets.bug.should == 'This is a bug'
503
+ product.feature_bullets.features.size.should == 2
504
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
505
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
506
+ end
507
+
508
+ it "should parse xml with single namespace" do
509
+ product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true)
510
+ product.title.should == "A Title"
511
+ product.feature_bullets.bug.should == 'This is a bug'
512
+ product.feature_bullets.features.size.should == 2
513
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
514
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
515
+ end
516
+
517
+ it "should parse xml with multiple namespaces" do
518
+ track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
519
+ track.highest_severity.should == 'SUCCESS'
520
+ track.more_data.should be_false
521
+ notification = track.notifications.first
522
+ notification.code.should == 0
523
+ notification.localized_message.should == 'Request was successfully processed.'
524
+ notification.message.should == 'Request was successfully processed.'
525
+ notification.severity.should == 'SUCCESS'
526
+ notification.source.should == 'trck'
527
+ detail = track.trackdetails.first
528
+ detail.carrier_code.should == 'FDXG'
529
+ detail.est_delivery.should == '2009-01-02T00:00:00'
530
+ detail.service_info.should == 'Ground-Package Returns Program-Domestic'
531
+ detail.status_code.should == 'OD'
532
+ detail.status_desc.should == 'On FedEx vehicle for delivery'
533
+ detail.tracking_number.should == '9611018034267800045212'
534
+ detail.weight.units.should == 'LB'
535
+ detail.weight.value.should == 2
536
+ events = detail.events
537
+ events.size.should == 10
538
+ first_event = events[0]
539
+ first_event.eventdescription.should == 'On FedEx vehicle for delivery'
540
+ first_event.eventtype.should == 'OD'
541
+ first_event.timestamp.should == '2009-01-02T06:00:00'
542
+ first_event.address.city.should == 'WICHITA'
543
+ first_event.address.countrycode.should == 'US'
544
+ first_event.address.residential.should be_false
545
+ first_event.address.state.should == 'KS'
546
+ first_event.address.zip.should == '67226'
547
+ last_event = events[-1]
548
+ last_event.eventdescription.should == 'In FedEx possession'
549
+ last_event.eventtype.should == 'IP'
550
+ last_event.timestamp.should == '2008-12-27T09:40:00'
551
+ last_event.address.city.should == 'LONGWOOD'
552
+ last_event.address.countrycode.should == 'US'
553
+ last_event.address.residential.should be_false
554
+ last_event.address.state.should == 'FL'
555
+ last_event.address.zip.should == '327506398'
556
+ track.tran_detail.cust_tran_id.should == '20090102-111321'
557
+ end
558
+
559
+ it "should be able to parse google analytics api xml" do
560
+ data = Analytics::Feed.parse(fixture_file('analytics.xml'))
561
+ data.id.should == 'http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com'
562
+ data.entries.size.should == 4
563
+
564
+ entry = data.entries[0]
565
+ entry.title.should == 'addictedtonew.com'
566
+ entry.properties.size.should == 4
567
+
568
+ property = entry.properties[0]
569
+ property.name.should == 'ga:accountId'
570
+ property.value.should == '85301'
571
+ end
572
+
573
+ it "should allow instantiating with a string" do
574
+ module StringFoo
575
+ class Bar
576
+ include HappyMapper
577
+ has_many :things, 'StringFoo::Thing'
578
+ end
579
+
580
+ class Thing
581
+ include HappyMapper
582
+ end
583
+ end
584
+ end
585
+
586
+ xit "should parse family search xml" do
587
+ tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
588
+ tree.version.should == '1.0.20071213.942'
589
+ tree.status_message.should == 'OK'
590
+ tree.status_code.should == '200'
591
+ # tree.people.size.should == 1
592
+ # tree.people.first.version.should == '1199378491000'
593
+ # tree.people.first.modified.should == Time.utc(2008, 1, 3, 16, 41, 31) # 2008-01-03T09:41:31-07:00
594
+ # tree.people.first.id.should == 'KWQS-BBQ'
595
+ end
596
+
597
+ describe 'nested elements with namespaces' do
598
+ module Namespaces
599
+ class Info
600
+ include HappyMapper
601
+ namespace 'http://schemas.google.com/analytics/2009'
602
+ element :category, String
603
+ end
604
+
605
+ class Alert
606
+ include HappyMapper
607
+ namespace 'http://schemas.google.com/analytics/2009'
608
+
609
+ element :identifier, String
610
+ element :severity, String, :namespace => false
611
+ has_one :info, Info
612
+ end
613
+ class Distribution
614
+ include HappyMapper
615
+
616
+ tag 'EDXLDistribution'
617
+ has_one :alert, Alert
618
+ end
619
+ end
620
+
621
+ def mapping
622
+ @mapping ||= Namespaces::Distribution.parse(fixture_file('nested_namespaces.xml'))
623
+ end
624
+
625
+ it "should parse elements with inline namespace" do
626
+ lambda { mapping }.should_not raise_error
627
+ end
628
+
629
+ it "should map elements with inline namespace" do
630
+ mapping.alert.identifier.should == 'CDC-2006-183'
631
+ end
632
+
633
+ it "should map sub elements of with nested namespace" do
634
+ mapping.alert.info.category.should == 'Health'
635
+ end
636
+
637
+ it "should map elements without a namespace" do
638
+ mapping.alert.severity.should == 'Severe'
639
+ end
640
+ end
641
+
642
+ describe "" do
643
+ before do
644
+ @user = User.new
645
+ end
646
+
647
+ it "should provide #to_xml_node" do
648
+ @user.should respond_to(:to_xml_node)
649
+ end
650
+
651
+ it "should generate XML tags" do
652
+ @user.to_xml_node.to_s(:indent => false).should == "<user/>"
653
+ end
654
+
655
+ it "should generate XML tags for elements" do
656
+ @user.name = "Maxim"
657
+ @user.to_xml_node.to_s(:indent => false).should == "<user><name>Maxim</name></user>"
658
+ end
659
+
660
+ it "should generate XML attributes for attributes" do
661
+ obj = FamilySearch::Person.new
662
+ obj.version = "1.2.3.4"
663
+ obj.to_xml_node.to_s(:indent => false).should == '<person version="1.2.3.4"/>'
664
+ end
665
+
666
+ it "should generate XML for has_one relationship" do
667
+ obj = FedEx::Event.new
668
+ obj.address = FedEx::Address.new
669
+ obj.to_xml_node.to_s(:indent => false).should == '<Events><Address/></Events>'
670
+ end
671
+
672
+ it "should generate XML for has_many relationship" do
673
+ obj = FeatureBullet.new
674
+ f1 = Feature.new
675
+ f1.name = "name1"
676
+ f2 = Feature.new
677
+ f2.name = "name2"
678
+ obj.features = [f1, f2]
679
+ obj.to_xml_node.to_s(:indent => false).should == '<features_bullets><feature><name>name1</name></feature><feature><name>name2</name></feature></features_bullets>'
680
+ end
681
+
682
+ it "should generate XML for has_many relationship and remove empty elements (without children and attributes)" do
683
+ obj = FeatureBullet.new
684
+ f1 = Feature.new
685
+ f2 = Feature.new
686
+ obj.features = [f1, f2]
687
+ obj.to_xml_node.to_s(:indent => false).should == '<features_bullets/>'
688
+ end
689
+
690
+ it "should generate helper tag for has_many if :group_tag option is true" do
691
+ obj = Groups::Group.new
692
+ ge1 = Groups::GroupElement.new
693
+ ge1.id = "id1"
694
+ ge2 = Groups::GroupElement.new
695
+ ge2.id = "id2"
696
+ obj.GroupElements = [ge1, ge2]
697
+ obj.to_xml_node.to_s(:indent => false).should == '<group><groupelements><groupelement id="id1"/><groupelement id="id2"/></groupelements></group>'
698
+ end
699
+
700
+ it "should generate helper tag for has_many if :group_tag option is true and remove empty elements (without children and attributes)" do
701
+ obj = Groups::Group.new
702
+ ge1 = Groups::GroupElement.new
703
+ ge2 = Groups::GroupElement.new
704
+ obj.GroupElements = [ge1, ge2]
705
+ obj.to_xml_node.to_s(:indent => false).should == '<group/>'
706
+ end
707
+
708
+ it "should provide #to_xml" do
709
+ @user.should respond_to(:to_xml)
710
+ end
711
+
712
+ it "should generate XML document" do
713
+ @user.name = "Maxim"
714
+ @user.to_xml.should == %Q(<?xml version="1.0" encoding="UTF-8"?>\n<user>\n <name>Maxim</name>\n</user>\n)
715
+ end
716
+
717
+ end
718
+
719
+ end