dam5s-happymapper 0.3.2

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.
@@ -0,0 +1,21 @@
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
+
17
+ it 'should know that it is NOT a text node' do
18
+ @attr.text_node?.should be_false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
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
+
17
+ it 'should know that it is NOT a text node' do
18
+ @attr.text_node?.should be_false
19
+ end
20
+ end
21
+ 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 = 'v2'
69
+ item.xpath.should == 'v2: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,660 @@
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 'dxp'
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 => 'dxp', :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 Address
38
+ include HappyMapper
39
+
40
+ tag 'address'
41
+ element :street, String
42
+ element :postcode, String
43
+ element :housenumber, String
44
+ element :city, String
45
+ element :country, String
46
+ end
47
+
48
+ class Feature
49
+ include HappyMapper
50
+ element :name, String, :tag => '.|.//text()'
51
+ end
52
+
53
+ class FeatureBullet
54
+ include HappyMapper
55
+
56
+ tag 'features_bullets'
57
+ has_many :features, Feature
58
+ element :bug, String
59
+ end
60
+
61
+ class Product
62
+ include HappyMapper
63
+
64
+ element :title, String
65
+ has_one :feature_bullets, FeatureBullet
66
+ has_one :address, Address
67
+ end
68
+
69
+ module FamilySearch
70
+ class AlternateIds
71
+ include HappyMapper
72
+
73
+ tag 'alternateIds'
74
+ has_many :ids, String, :tag => 'id'
75
+ end
76
+
77
+ class Information
78
+ include HappyMapper
79
+
80
+ has_one :alternateIds, AlternateIds
81
+ end
82
+
83
+ class Person
84
+ include HappyMapper
85
+
86
+ attribute :version, String
87
+ attribute :modified, Time
88
+ attribute :id, String
89
+ has_one :information, Information
90
+ end
91
+
92
+ class Persons
93
+ include HappyMapper
94
+ has_many :person, Person
95
+ end
96
+
97
+ class FamilyTree
98
+ include HappyMapper
99
+
100
+ tag 'familytree'
101
+ attribute :version, String
102
+ attribute :status_message, String, :tag => 'statusMessage'
103
+ attribute :status_code, String, :tag => 'statusCode'
104
+ has_one :persons, Persons
105
+ end
106
+ end
107
+
108
+ module FedEx
109
+ class Address
110
+ include HappyMapper
111
+
112
+ tag 'Address'
113
+ namespace 'v2'
114
+ element :city, String, :tag => 'City'
115
+ element :state, String, :tag => 'StateOrProvinceCode'
116
+ element :zip, String, :tag => 'PostalCode'
117
+ element :countrycode, String, :tag => 'CountryCode'
118
+ element :residential, Boolean, :tag => 'Residential'
119
+ end
120
+
121
+ class Event
122
+ include HappyMapper
123
+
124
+ tag 'Events'
125
+ namespace 'v2'
126
+ element :timestamp, String, :tag => 'Timestamp'
127
+ element :eventtype, String, :tag => 'EventType'
128
+ element :eventdescription, String, :tag => 'EventDescription'
129
+ has_one :address, Address
130
+ end
131
+
132
+ class PackageWeight
133
+ include HappyMapper
134
+
135
+ tag 'PackageWeight'
136
+ namespace 'v2'
137
+ element :units, String, :tag => 'Units'
138
+ element :value, Integer, :tag => 'Value'
139
+ end
140
+
141
+ class TrackDetails
142
+ include HappyMapper
143
+
144
+ tag 'TrackDetails'
145
+ namespace 'v2'
146
+ element :tracking_number, String, :tag => 'TrackingNumber'
147
+ element :status_code, String, :tag => 'StatusCode'
148
+ element :status_desc, String, :tag => 'StatusDescription'
149
+ element :carrier_code, String, :tag => 'CarrierCode'
150
+ element :service_info, String, :tag => 'ServiceInfo'
151
+ has_one :weight, PackageWeight, :tag => 'PackageWeight'
152
+ element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
153
+ has_many :events, Event
154
+ end
155
+
156
+ class Notification
157
+ include HappyMapper
158
+
159
+ tag 'Notifications'
160
+ namespace 'v2'
161
+ element :severity, String, :tag => 'Severity'
162
+ element :source, String, :tag => 'Source'
163
+ element :code, Integer, :tag => 'Code'
164
+ element :message, String, :tag => 'Message'
165
+ element :localized_message, String, :tag => 'LocalizedMessage'
166
+ end
167
+
168
+ class TransactionDetail
169
+ include HappyMapper
170
+
171
+ tag 'TransactionDetail'
172
+ namespace 'v2'
173
+ element :cust_tran_id, String, :tag => 'CustomerTransactionId'
174
+ end
175
+
176
+ class TrackReply
177
+ include HappyMapper
178
+
179
+ tag 'TrackReply'
180
+ namespace 'v2'
181
+ element :highest_severity, String, :tag => 'HighestSeverity'
182
+ element :more_data, Boolean, :tag => 'MoreData'
183
+ has_many :notifications, Notification, :tag => 'Notifications'
184
+ has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
185
+ has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
186
+ end
187
+ end
188
+
189
+ class Place
190
+ include HappyMapper
191
+ element :name, String
192
+ end
193
+
194
+ class Radar
195
+ include HappyMapper
196
+ has_many :places, Place, :tag => :place
197
+ end
198
+
199
+ class Post
200
+ include HappyMapper
201
+
202
+ attribute :href, String
203
+ attribute :hash, String
204
+ attribute :description, String
205
+ attribute :tag, String
206
+ attribute :time, Time
207
+ attribute :others, Integer
208
+ attribute :extended, String
209
+ end
210
+
211
+ class User
212
+ include HappyMapper
213
+
214
+ element :id, Integer
215
+ element :name, String
216
+ element :screen_name, String
217
+ element :location, String
218
+ element :description, String
219
+ element :profile_image_url, String
220
+ element :url, String
221
+ element :protected, Boolean
222
+ element :followers_count, Integer
223
+ end
224
+
225
+ class Status
226
+ include HappyMapper
227
+
228
+ element :id, Integer
229
+ element :text, String
230
+ element :created_at, Time
231
+ element :source, String
232
+ element :truncated, Boolean
233
+ element :in_reply_to_status_id, Integer
234
+ element :in_reply_to_user_id, Integer
235
+ element :favorited, Boolean
236
+ element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
237
+ has_one :user, User
238
+ end
239
+
240
+ class CurrentWeather
241
+ include HappyMapper
242
+
243
+ tag 'ob'
244
+ namespace 'aws'
245
+ element :temperature, Integer, :tag => 'temp'
246
+ element :feels_like, Integer, :tag => 'feels-like'
247
+ element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
248
+ end
249
+
250
+ class Country
251
+ include HappyMapper
252
+
253
+ attribute :code, String
254
+ text_node :name, String
255
+ end
256
+
257
+ class Address
258
+ include HappyMapper
259
+
260
+ tag 'address'
261
+ element :street, String
262
+ element :postcode, String
263
+ element :housenumber, String
264
+ element :city, String
265
+ has_one :country, Country
266
+ end
267
+
268
+ # for type coercion
269
+ class ProductGroup < String; end
270
+
271
+ module PITA
272
+ class Item
273
+ include HappyMapper
274
+
275
+ tag 'Item' # if you put class in module you need tag
276
+ element :asin, String, :tag => 'ASIN'
277
+ element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
278
+ element :manufacturer, String, :tag => 'Manufacturer', :deep => true
279
+ element :point, String, :tag => 'point', :namespace => 'georss'
280
+ element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
281
+ end
282
+
283
+ class Items
284
+ include HappyMapper
285
+
286
+ tag 'Items' # if you put class in module you need tag
287
+ element :total_results, Integer, :tag => 'TotalResults'
288
+ element :total_pages, Integer, :tag => 'TotalPages'
289
+ has_many :items, Item
290
+ end
291
+ end
292
+
293
+ module GitHub
294
+ class Commit
295
+ include HappyMapper
296
+
297
+ tag "commit"
298
+ element :url, String
299
+ element :tree, String
300
+ element :message, String
301
+ element :id, String
302
+ element :'committed-date', Date
303
+ end
304
+ end
305
+
306
+ module QuarterTest
307
+ class Quarter
308
+ include HappyMapper
309
+
310
+ element :start, String
311
+ end
312
+
313
+ class Details
314
+ include HappyMapper
315
+
316
+ element :round, Integer
317
+ element :quarter, Integer
318
+ end
319
+
320
+ class Game
321
+ include HappyMapper
322
+
323
+ # in an ideal world, the following elements would all be
324
+ # called 'quarter' with an attribute indicating which quarter
325
+ # it represented, but the refactoring that allows a single class
326
+ # to be used for all these differently named elements is the next
327
+ # best thing
328
+ has_one :details, QuarterTest::Details
329
+ has_one :q1, QuarterTest::Quarter, :tag => 'q1'
330
+ has_one :q2, QuarterTest::Quarter, :tag => 'q2'
331
+ has_one :q3, QuarterTest::Quarter, :tag => 'q3'
332
+ has_one :q4, QuarterTest::Quarter, :tag => 'q4'
333
+ end
334
+ end
335
+
336
+ describe HappyMapper do
337
+
338
+ describe "being included into another class" do
339
+ before do
340
+ @klass = Class.new do
341
+ include HappyMapper
342
+
343
+ def self.to_s
344
+ 'Foo'
345
+ end
346
+ end
347
+ end
348
+
349
+ class Foo; include HappyMapper end
350
+
351
+ it "should set attributes to an array" do
352
+ @klass.attributes.should == []
353
+ end
354
+
355
+ it "should set @elements to a hash" do
356
+ @klass.elements.should == []
357
+ end
358
+
359
+ it "should allow adding an attribute" do
360
+ lambda {
361
+ @klass.attribute :name, String
362
+ }.should change(@klass, :attributes)
363
+ end
364
+
365
+ it "should allow adding an attribute containing a dash" do
366
+ lambda {
367
+ @klass.attribute :'bar-baz', String
368
+ }.should change(@klass, :attributes)
369
+ end
370
+
371
+ it "should be able to get all attributes in array" do
372
+ @klass.attribute :name, String
373
+ @klass.attributes.size.should == 1
374
+ end
375
+
376
+ it "should allow adding an element" do
377
+ lambda {
378
+ @klass.element :name, String
379
+ }.should change(@klass, :elements)
380
+ end
381
+
382
+ it "should allow adding an element containing a dash" do
383
+ lambda {
384
+ @klass.element :'bar-baz', String
385
+ }.should change(@klass, :elements)
386
+
387
+ end
388
+
389
+ it "should be able to get all elements in array" do
390
+ @klass.element(:name, String)
391
+ @klass.elements.size.should == 1
392
+ end
393
+
394
+ it "should allow has one association" do
395
+ @klass.has_one(:user, User)
396
+ element = @klass.elements.first
397
+ element.name.should == 'user'
398
+ element.type.should == User
399
+ element.options[:single] = true
400
+ end
401
+
402
+ it "should allow has many association" do
403
+ @klass.has_many(:users, User)
404
+ element = @klass.elements.first
405
+ element.name.should == 'users'
406
+ element.type.should == User
407
+ element.options[:single] = false
408
+ end
409
+
410
+ it "should default tag name to lowercase class" do
411
+ @klass.tag_name.should == 'foo'
412
+ end
413
+
414
+ it "should default tag name of class in modules to the last constant lowercase" do
415
+ module Bar; class Baz; include HappyMapper; end; end
416
+ Bar::Baz.tag_name.should == 'baz'
417
+ end
418
+
419
+ it "should allow setting tag name" do
420
+ @klass.tag('FooBar')
421
+ @klass.tag_name.should == 'FooBar'
422
+ end
423
+
424
+ it "should allow setting a namespace" do
425
+ @klass.namespace(namespace = "foo")
426
+ @klass.namespace.should == namespace
427
+ end
428
+
429
+ it "should provide #parse" do
430
+ @klass.should respond_to(:parse)
431
+ end
432
+ end
433
+
434
+ describe "#attributes" do
435
+ it "should only return attributes for the current class" do
436
+ Post.attributes.size.should == 7
437
+ Status.attributes.size.should == 0
438
+ end
439
+ end
440
+
441
+ describe "#elements" do
442
+ it "should only return elements for the current class" do
443
+ Post.elements.size.should == 0
444
+ Status.elements.size.should == 10
445
+ end
446
+ end
447
+
448
+ it "should parse xml attributes into ruby objects" do
449
+ posts = Post.parse(fixture_file('posts.xml'))
450
+ posts.size.should == 20
451
+ first = posts.first
452
+ first.href.should == 'http://roxml.rubyforge.org/'
453
+ first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
454
+ first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
455
+ first.tag.should == 'ruby xml gems mapping'
456
+ first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
457
+ first.others.should == 56
458
+ 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.'
459
+ end
460
+
461
+ it "should parse xml elements to ruby objcts" do
462
+ statuses = Status.parse(fixture_file('statuses.xml'))
463
+ statuses.size.should == 20
464
+ first = statuses.first
465
+ first.id.should == 882281424
466
+ first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12)
467
+ first.source.should == 'web'
468
+ first.truncated.should be_false
469
+ first.in_reply_to_status_id.should == 1234
470
+ first.in_reply_to_user_id.should == 12345
471
+ first.favorited.should be_false
472
+ first.user.id.should == 4243
473
+ first.user.name.should == 'John Nunemaker'
474
+ first.user.screen_name.should == 'jnunemaker'
475
+ first.user.location.should == 'Mishawaka, IN, US'
476
+ first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
477
+ first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
478
+ first.user.url.should == 'http://addictedtonew.com'
479
+ first.user.protected.should be_false
480
+ first.user.followers_count.should == 486
481
+ end
482
+
483
+ it "should parse xml containing the desired element as root node" do
484
+ address = Address.parse(fixture_file('address.xml'), :single => true)
485
+ address.street.should == 'Milchstrasse'
486
+ address.postcode.should == '26131'
487
+ address.housenumber.should == '23'
488
+ address.city.should == 'Oldenburg'
489
+ address.country.class.should == Country
490
+ end
491
+
492
+ it "should parse text node correctly" do
493
+ address = Address.parse(fixture_file('address.xml'), :single => true)
494
+ address.country.name.should == 'Germany'
495
+ address.country.code.should == 'de'
496
+ end
497
+
498
+ it "should parse xml with default namespace (amazon)" do
499
+ file_contents = fixture_file('pita.xml')
500
+ items = PITA::Items.parse(file_contents, :single => true)
501
+ items.total_results.should == 22
502
+ items.total_pages.should == 3
503
+ first = items.items[0]
504
+ second = items.items[1]
505
+ first.asin.should == '0321480791'
506
+ first.point.should == '38.5351715088 -121.7948684692'
507
+ first.detail_page_url.should be_a_kind_of(URI)
508
+ 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'
509
+ first.manufacturer.should == 'Addison-Wesley Professional'
510
+ first.product_group.should == '<ProductGroup>Book</ProductGroup>'
511
+ second.asin.should == '047022388X'
512
+ second.manufacturer.should == 'Wrox'
513
+ end
514
+
515
+ it "should parse xml that has attributes of elements" do
516
+ items = CurrentWeather.parse(fixture_file('current_weather.xml'))
517
+ first = items[0]
518
+ first.temperature.should == 51
519
+ first.feels_like.should == 51
520
+ first.current_condition.should == 'Sunny'
521
+ first.current_condition.icon.should == 'http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif'
522
+ end
523
+
524
+ it "should parse xml with nested elements" do
525
+ radars = Radar.parse(fixture_file('radar.xml'))
526
+ first = radars[0]
527
+ first.places.size.should == 1
528
+ first.places[0].name.should == 'Store'
529
+ second = radars[1]
530
+ second.places.size.should == 0
531
+ third = radars[2]
532
+ third.places.size.should == 2
533
+ third.places[0].name.should == 'Work'
534
+ third.places[1].name.should == 'Home'
535
+ end
536
+
537
+ it "should parse xml with element name different to class name" do
538
+ game = QuarterTest::Game.parse(fixture_file('quarters.xml'))
539
+ game.q1.start.should == '4:40:15 PM'
540
+ game.q2.start.should == '5:18:53 PM'
541
+ end
542
+
543
+ it "should parse xml that has elements with dashes" do
544
+ commit = GitHub::Commit.parse(fixture_file('commit.xml'))
545
+ commit.message.should == "move commands.rb and helpers.rb into commands/ dir"
546
+ commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
547
+ commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
548
+ commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00")
549
+ commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76"
550
+ end
551
+
552
+ it "should parse xml with no namespace" do
553
+ product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true)
554
+ product.title.should == "A Title"
555
+ product.feature_bullets.bug.should == 'This is a bug'
556
+ product.feature_bullets.features.size.should == 2
557
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
558
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
559
+ end
560
+
561
+ it "should parse xml with default namespace" do
562
+ product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
563
+ product.title.should == "A Title"
564
+ product.feature_bullets.bug.should == 'This is a bug'
565
+ product.feature_bullets.features.size.should == 2
566
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
567
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
568
+ end
569
+
570
+ it "should parse xml with single namespace" do
571
+ product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true)
572
+ product.title.should == "A Title"
573
+ product.feature_bullets.bug.should == 'This is a bug'
574
+ product.feature_bullets.features.size.should == 2
575
+ product.feature_bullets.features[0].name.should == 'This is feature text 1'
576
+ product.feature_bullets.features[1].name.should == 'This is feature text 2'
577
+ end
578
+
579
+ it "should parse xml with multiple namespaces" do
580
+ track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
581
+ track.highest_severity.should == 'SUCCESS'
582
+ track.more_data.should be_false
583
+ notification = track.notifications.first
584
+ notification.code.should == 0
585
+ notification.localized_message.should == 'Request was successfully processed.'
586
+ notification.message.should == 'Request was successfully processed.'
587
+ notification.severity.should == 'SUCCESS'
588
+ notification.source.should == 'trck'
589
+ detail = track.trackdetails.first
590
+ detail.carrier_code.should == 'FDXG'
591
+ detail.est_delivery.should == '2009-01-02T00:00:00'
592
+ detail.service_info.should == 'Ground-Package Returns Program-Domestic'
593
+ detail.status_code.should == 'OD'
594
+ detail.status_desc.should == 'On FedEx vehicle for delivery'
595
+ detail.tracking_number.should == '9611018034267800045212'
596
+ detail.weight.units.should == 'LB'
597
+ detail.weight.value.should == 2
598
+ events = detail.events
599
+ events.size.should == 10
600
+ first_event = events[0]
601
+ first_event.eventdescription.should == 'On FedEx vehicle for delivery'
602
+ first_event.eventtype.should == 'OD'
603
+ first_event.timestamp.should == '2009-01-02T06:00:00'
604
+ first_event.address.city.should == 'WICHITA'
605
+ first_event.address.countrycode.should == 'US'
606
+ first_event.address.residential.should be_false
607
+ first_event.address.state.should == 'KS'
608
+ first_event.address.zip.should == '67226'
609
+ last_event = events[-1]
610
+ last_event.eventdescription.should == 'In FedEx possession'
611
+ last_event.eventtype.should == 'IP'
612
+ last_event.timestamp.should == '2008-12-27T09:40:00'
613
+ last_event.address.city.should == 'LONGWOOD'
614
+ last_event.address.countrycode.should == 'US'
615
+ last_event.address.residential.should be_false
616
+ last_event.address.state.should == 'FL'
617
+ last_event.address.zip.should == '327506398'
618
+ track.tran_detail.cust_tran_id.should == '20090102-111321'
619
+ end
620
+
621
+ it "should be able to parse google analytics api xml" do
622
+ data = Analytics::Feed.parse(fixture_file('analytics.xml'))
623
+ data.id.should == 'http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com'
624
+ data.entries.size.should == 4
625
+
626
+ entry = data.entries[0]
627
+ entry.title.should == 'addictedtonew.com'
628
+ entry.properties.size.should == 4
629
+
630
+ property = entry.properties[0]
631
+ property.name.should == 'ga:accountId'
632
+ property.value.should == '85301'
633
+ end
634
+
635
+ it "should allow instantiating with a string" do
636
+ module StringFoo
637
+ class Bar
638
+ include HappyMapper
639
+ has_many :things, 'StringFoo::Thing'
640
+ end
641
+
642
+ class Thing
643
+ include HappyMapper
644
+ end
645
+ end
646
+ end
647
+
648
+ xit "should parse family search xml" do
649
+ tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
650
+ tree.version.should == '1.0.20071213.942'
651
+ tree.status_message.should == 'OK'
652
+ tree.status_code.should == '200'
653
+ tree.persons.person.size.should == 1
654
+ tree.persons.person.first.version.should == '1199378491000'
655
+ tree.persons.person.first.modified.should == Time.utc(2008, 1, 3, 16, 41, 31) # 2008-01-03T09:41:31-07:00
656
+ tree.persons.person.first.id.should == 'KWQS-BBQ'
657
+ tree.persons.person.first.information.alternateIds.ids.should_not be_kind_of(String)
658
+ tree.persons.person.first.information.alternateIds.ids.size.should == 8
659
+ end
660
+ end