nokogiri-happymapper 0.6.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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,1129 +0,0 @@
1
- require 'spec_helper'
2
- require 'uri'
3
-
4
- module Analytics
5
- class Property
6
- include HappyMapper
7
-
8
- tag 'property'
9
- namespace 'dxp'
10
- attribute :name, String
11
- attribute :value, String
12
- end
13
-
14
- class Goal
15
- include HappyMapper
16
-
17
- # Google Analytics does a dirtry trick where a user with no goals
18
- # returns a profile without any goals data or the declared namespace
19
- # which means Nokogiri does not pick up the namespace automatically.
20
- # To fix this, we manually register the namespace to avoid bad XPath
21
- # expression. Dirty, but works.
22
-
23
- register_namespace 'ga', 'http://schemas.google.com/ga/2009'
24
- namespace 'ga'
25
-
26
- tag 'goal'
27
- attribute :active, Boolean
28
- attribute :name, String
29
- attribute :number, Integer
30
- attribute :value, Float
31
-
32
- def clean_name
33
- name.gsub(/ga:/, '')
34
- end
35
- end
36
-
37
- class Profile
38
- include HappyMapper
39
-
40
- tag 'entry'
41
- element :title, String
42
- element :tableId, String, :namespace => 'dxp'
43
-
44
- has_many :properties, Property
45
- has_many :goals, Goal
46
- end
47
-
48
-
49
- class Entry
50
- include HappyMapper
51
-
52
- tag 'entry'
53
- element :id, String
54
- element :updated, DateTime
55
- element :title, String
56
- element :table_id, String, :namespace => 'dxp', :tag => 'tableId'
57
- has_many :properties, Property
58
- end
59
-
60
- class Feed
61
- include HappyMapper
62
-
63
- tag 'feed'
64
- element :id, String
65
- element :updated, DateTime
66
- element :title, String
67
- has_many :entries, Entry
68
- end
69
- end
70
-
71
- module Atom
72
- class Feed
73
- include HappyMapper
74
- tag 'feed'
75
-
76
- attribute :xmlns, String, :single => true
77
- element :id, String, :single => true
78
- element :title, String, :single => true
79
- element :updated, DateTime, :single => true
80
- element :link, String, :single => false, :attributes => {
81
- :rel => String,
82
- :type => String,
83
- :href => String
84
- }
85
- # has_many :entries, Entry # nothing interesting in the entries
86
- end
87
- end
88
-
89
- class Country
90
- include HappyMapper
91
-
92
- attribute :code, String
93
- content :name, String
94
- end
95
-
96
-
97
- class State
98
- include HappyMapper
99
- end
100
-
101
- class Address
102
- include HappyMapper
103
-
104
- attr_accessor :xml_value
105
- attr_accessor :xml_content
106
-
107
- tag 'address'
108
- element :street, String
109
- element :postcode, String
110
- element :housenumber, String
111
- element :city, String
112
- has_one :country, Country
113
- has_one :state, State
114
- end
115
-
116
- class Feature
117
- include HappyMapper
118
- element :name, String, :xpath => './/text()'
119
- end
120
-
121
- class FeatureBullet
122
- include HappyMapper
123
-
124
- tag 'features_bullets'
125
- has_many :features, Feature
126
- element :bug, String
127
- end
128
-
129
- class Product
130
- include HappyMapper
131
-
132
- element :title, String
133
- has_one :feature_bullets, FeatureBullet
134
- has_one :address, Address
135
- end
136
-
137
- class Rate
138
- include HappyMapper
139
- end
140
-
141
- module FamilySearch
142
- class AlternateIds
143
- include HappyMapper
144
-
145
- tag 'alternateIds'
146
- has_many :ids, String, :tag => 'id'
147
- end
148
-
149
- class Information
150
- include HappyMapper
151
-
152
- has_one :alternateIds, AlternateIds
153
- end
154
-
155
- class Person
156
- include HappyMapper
157
-
158
- attribute :version, String
159
- attribute :modified, Time
160
- attribute :id, String
161
- has_one :information, Information
162
- end
163
-
164
- class Persons
165
- include HappyMapper
166
- has_many :person, Person
167
- end
168
-
169
- class FamilyTree
170
- include HappyMapper
171
-
172
- tag 'familytree'
173
- attribute :version, String
174
- attribute :status_message, String, :tag => 'statusMessage'
175
- attribute :status_code, String, :tag => 'statusCode'
176
- has_one :persons, Persons
177
- end
178
- end
179
-
180
- module FedEx
181
- class Address
182
- include HappyMapper
183
-
184
- tag 'Address'
185
- namespace 'v2'
186
- element :city, String, :tag => 'City'
187
- element :state, String, :tag => 'StateOrProvinceCode'
188
- element :zip, String, :tag => 'PostalCode'
189
- element :countrycode, String, :tag => 'CountryCode'
190
- element :residential, Boolean, :tag => 'Residential'
191
- end
192
-
193
- class Event
194
- include HappyMapper
195
-
196
- tag 'Events'
197
- namespace 'v2'
198
- element :timestamp, String, :tag => 'Timestamp'
199
- element :eventtype, String, :tag => 'EventType'
200
- element :eventdescription, String, :tag => 'EventDescription'
201
- has_one :address, Address
202
- end
203
-
204
- class PackageWeight
205
- include HappyMapper
206
-
207
- tag 'PackageWeight'
208
- namespace 'v2'
209
- element :units, String, :tag => 'Units'
210
- element :value, Integer, :tag => 'Value'
211
- end
212
-
213
- class TrackDetails
214
- include HappyMapper
215
-
216
- tag 'TrackDetails'
217
- namespace 'v2'
218
- element :tracking_number, String, :tag => 'TrackingNumber'
219
- element :status_code, String, :tag => 'StatusCode'
220
- element :status_desc, String, :tag => 'StatusDescription'
221
- element :carrier_code, String, :tag => 'CarrierCode'
222
- element :service_info, String, :tag => 'ServiceInfo'
223
- has_one :weight, PackageWeight, :tag => 'PackageWeight'
224
- element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
225
- has_many :events, Event
226
- end
227
-
228
- class Notification
229
- include HappyMapper
230
-
231
- tag 'Notifications'
232
- namespace 'v2'
233
- element :severity, String, :tag => 'Severity'
234
- element :source, String, :tag => 'Source'
235
- element :code, Integer, :tag => 'Code'
236
- element :message, String, :tag => 'Message'
237
- element :localized_message, String, :tag => 'LocalizedMessage'
238
- end
239
-
240
- class TransactionDetail
241
- include HappyMapper
242
-
243
- tag 'TransactionDetail'
244
- namespace 'v2'
245
- element :cust_tran_id, String, :tag => 'CustomerTransactionId'
246
- end
247
-
248
- class TrackReply
249
- include HappyMapper
250
-
251
- tag 'TrackReply'
252
- namespace 'v2'
253
- element :highest_severity, String, :tag => 'HighestSeverity'
254
- element :more_data, Boolean, :tag => 'MoreData'
255
- has_many :notifications, Notification, :tag => 'Notifications'
256
- has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
257
- has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
258
- end
259
- end
260
-
261
- class Place
262
- include HappyMapper
263
- element :name, String
264
- end
265
-
266
- class Radar
267
- include HappyMapper
268
- has_many :places, Place, :tag => :place
269
- end
270
-
271
- class Post
272
- include HappyMapper
273
-
274
- attribute :href, String
275
- attribute :hash, String
276
- attribute :description, String
277
- attribute :tag, String
278
- attribute :time, Time
279
- attribute :others, Integer
280
- attribute :extended, String
281
- end
282
-
283
- class User
284
- include HappyMapper
285
-
286
- element :id, Integer
287
- element :name, String
288
- element :screen_name, String
289
- element :location, String
290
- element :description, String
291
- element :profile_image_url, String
292
- element :url, String
293
- element :protected, Boolean
294
- element :followers_count, Integer
295
- end
296
-
297
- class Status
298
- include HappyMapper
299
-
300
- register_namespace 'fake', "faka:namespace"
301
-
302
- element :id, Integer
303
- element :text, String
304
- element :created_at, Time
305
- element :source, String
306
- element :truncated, Boolean
307
- element :in_reply_to_status_id, Integer
308
- element :in_reply_to_user_id, Integer
309
- element :favorited, Boolean
310
- element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
311
- has_one :user, User
312
- end
313
-
314
- class CurrentWeather
315
- include HappyMapper
316
-
317
- tag 'ob'
318
- namespace 'aws'
319
- element :temperature, Integer, :tag => 'temp'
320
- element :feels_like, Integer, :tag => 'feels-like'
321
- element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
322
- end
323
-
324
- # for type coercion
325
- class ProductGroup < String; end
326
-
327
- module PITA
328
- class Item
329
- include HappyMapper
330
-
331
- tag 'Item' # if you put class in module you need tag
332
- element :asin, String, :tag => 'ASIN'
333
- element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
334
- element :manufacturer, String, :tag => 'Manufacturer', :deep => true
335
- element :point, String, :tag => 'point', :namespace => 'georss'
336
- element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
337
- end
338
-
339
- class Items
340
- include HappyMapper
341
-
342
- tag 'Items' # if you put class in module you need tag
343
- element :total_results, Integer, :tag => 'TotalResults'
344
- element :total_pages, Integer, :tag => 'TotalPages'
345
- has_many :items, Item
346
- end
347
- end
348
-
349
- module GitHub
350
- class Commit
351
- include HappyMapper
352
-
353
- tag "commit"
354
- element :url, String
355
- element :tree, String
356
- element :message, String
357
- element :id, String
358
- element :'committed-date', Date
359
- end
360
- end
361
-
362
- module QuarterTest
363
- class Quarter
364
- include HappyMapper
365
-
366
- element :start, String
367
- end
368
-
369
- class Details
370
- include HappyMapper
371
-
372
- element :round, Integer
373
- element :quarter, Integer
374
- end
375
-
376
- class Game
377
- include HappyMapper
378
-
379
- # in an ideal world, the following elements would all be
380
- # called 'quarter' with an attribute indicating which quarter
381
- # it represented, but the refactoring that allows a single class
382
- # to be used for all these differently named elements is the next
383
- # best thing
384
- has_one :details, QuarterTest::Details
385
- has_one :q1, QuarterTest::Quarter, :tag => 'q1'
386
- has_one :q2, QuarterTest::Quarter, :tag => 'q2'
387
- has_one :q3, QuarterTest::Quarter, :tag => 'q3'
388
- has_one :q4, QuarterTest::Quarter, :tag => 'q4'
389
- end
390
- end
391
-
392
- # To check for multiple primitives
393
- class Artist
394
- include HappyMapper
395
-
396
- tag 'artist'
397
- element :images, String, :tag => "image", :single => false
398
- element :name, String
399
- end
400
-
401
- class Location
402
- include HappyMapper
403
-
404
- tag 'point'
405
- namespace "geo"
406
- element :latitude, String, :tag => "lat"
407
- end
408
-
409
- # Testing the XmlContent type
410
- module Dictionary
411
- class Variant
412
- include HappyMapper
413
- tag 'var'
414
- has_xml_content
415
-
416
- def to_html
417
- xml_content.gsub('<tag>','<em>').gsub('</tag>','</em>')
418
- end
419
- end
420
-
421
- class Definition
422
- include HappyMapper
423
-
424
- tag 'def'
425
- element :text, XmlContent, :tag => 'dtext'
426
- end
427
-
428
- class Record
429
- include HappyMapper
430
-
431
- tag 'record'
432
- has_many :definitions, Definition
433
- has_many :variants, Variant, :tag => 'var'
434
- end
435
- end
436
-
437
- module AmbigousItems
438
- class Item
439
- include HappyMapper
440
-
441
- tag 'item'
442
- element :name, String
443
- element :item, String
444
- end
445
- end
446
-
447
- class PublishOptions
448
- include HappyMapper
449
-
450
- tag 'publishOptions'
451
-
452
- element :author, String, :tag => 'author'
453
-
454
- element :draft, Boolean, :tag => 'draft'
455
- element :scheduled_day, String, :tag => 'scheduledDay'
456
- element :scheduled_time, String, :tag => 'scheduledTime'
457
- element :published_day, String, :tag => 'publishDisplayDay'
458
- element :published_time, String, :tag => 'publishDisplayTime'
459
- element :created_day, String, :tag => 'publishDisplayDay'
460
- element :created_time, String, :tag => 'publishDisplayTime'
461
-
462
- end
463
-
464
- class Article
465
- include HappyMapper
466
-
467
- tag 'Article'
468
- namespace 'article'
469
-
470
- attr_writer :xml_value
471
-
472
- element :title, String
473
- element :text, String
474
- has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
475
- has_many :galleries, 'Gallery', :tag => 'Gallery', :namespace => 'gallery'
476
-
477
- element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
478
-
479
- end
480
-
481
- class PartiallyBadArticle
482
- include HappyMapper
483
-
484
- attr_writer :xml_value
485
-
486
- tag 'Article'
487
- namespace 'article'
488
-
489
- element :title, String
490
- element :text, String
491
- has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
492
- has_many :videos, 'Video', :tag => 'Video', :namespace => 'video'
493
-
494
- element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
495
-
496
- end
497
-
498
- class Photo
499
- include HappyMapper
500
-
501
- tag 'Photo'
502
- namespace 'photo'
503
-
504
- attr_writer :xml_value
505
-
506
- element :title, String
507
- element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'photo'
508
-
509
- end
510
-
511
- class Gallery
512
- include HappyMapper
513
-
514
- tag 'Gallery'
515
- namespace 'gallery'
516
-
517
- attr_writer :xml_value
518
-
519
- element :title, String
520
-
521
- end
522
-
523
- class Video
524
- include HappyMapper
525
-
526
- tag 'Video'
527
- namespace 'video'
528
-
529
- attr_writer :xml_value
530
-
531
- element :title, String
532
- element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'video'
533
-
534
- end
535
-
536
- class OptionalAttribute
537
- include HappyMapper
538
- tag 'address'
539
-
540
- attribute :street, String
541
- end
542
-
543
- class DefaultNamespaceCombi
544
- include HappyMapper
545
-
546
-
547
- register_namespace 'bk', "urn:loc.gov:books"
548
- register_namespace 'isbn', "urn:ISBN:0-395-36341-6"
549
- register_namespace 'p', "urn:loc.gov:people"
550
- namespace 'bk'
551
-
552
- tag 'book'
553
-
554
- element :title, String, :namespace => 'bk', :tag => "title"
555
- element :number, String, :namespace => 'isbn', :tag => "number"
556
- element :author, String, :namespace => 'p', :tag => "author"
557
- end
558
-
559
- describe HappyMapper do
560
-
561
- describe "being included into another class" do
562
- before do
563
- @klass = Class.new do
564
- include HappyMapper
565
-
566
- def self.to_s
567
- 'Boo'
568
- end
569
- end
570
- end
571
-
572
- class Boo; include HappyMapper end
573
-
574
- it "should set attributes to an array" do
575
- expect(@klass.attributes).to eq([])
576
- end
577
-
578
- it "should set @elements to a hash" do
579
- expect(@klass.elements).to eq([])
580
- end
581
-
582
- it "should allow adding an attribute" do
583
- expect {
584
- @klass.attribute :name, String
585
- }.to change(@klass, :attributes)
586
- end
587
-
588
- it "should allow adding an attribute containing a dash" do
589
- expect {
590
- @klass.attribute :'bar-baz', String
591
- }.to change(@klass, :attributes)
592
- end
593
-
594
- it "should be able to get all attributes in array" do
595
- @klass.attribute :name, String
596
- expect(@klass.attributes.size).to eq(1)
597
- end
598
-
599
- it "should allow adding an element" do
600
- expect {
601
- @klass.element :name, String
602
- }.to change(@klass, :elements)
603
- end
604
-
605
- it "should allow adding an element containing a dash" do
606
- expect {
607
- @klass.element :'bar-baz', String
608
- }.to change(@klass, :elements)
609
-
610
- end
611
-
612
- it "should be able to get all elements in array" do
613
- @klass.element(:name, String)
614
- expect(@klass.elements.size).to eq(1)
615
- end
616
-
617
- it "should allow has one association" do
618
- @klass.has_one(:user, User)
619
- element = @klass.elements.first
620
- expect(element.name).to eq('user')
621
- expect(element.type).to eq(User)
622
- expect(element.options[:single]).to eq(true)
623
- end
624
-
625
- it "should allow has many association" do
626
- @klass.has_many(:users, User)
627
- element = @klass.elements.first
628
- expect(element.name).to eq('users')
629
- expect(element.type).to eq(User)
630
- expect(element.options[:single]).to eq(false)
631
- end
632
-
633
- it "should default tag name to lowercase class" do
634
- expect(@klass.tag_name).to eq('boo')
635
- end
636
-
637
- it "should default tag name of class in modules to the last constant lowercase" do
638
- module Bar; class Baz; include HappyMapper; end; end
639
- expect(Bar::Baz.tag_name).to eq('baz')
640
- end
641
-
642
- it "should allow setting tag name" do
643
- @klass.tag('FooBar')
644
- expect(@klass.tag_name).to eq('FooBar')
645
- end
646
-
647
- it "should allow setting a namespace" do
648
- @klass.namespace(namespace = "boo")
649
- expect(@klass.namespace).to eq(namespace)
650
- end
651
-
652
- it "should provide #parse" do
653
- expect(@klass).to respond_to(:parse)
654
- end
655
- end
656
-
657
- describe "#attributes" do
658
- it "should only return attributes for the current class" do
659
- expect(Post.attributes.size).to eq(7)
660
- expect(Status.attributes.size).to eq(0)
661
- end
662
- end
663
-
664
- describe "#elements" do
665
- it "should only return elements for the current class" do
666
- expect(Post.elements.size).to eq(0)
667
- expect(Status.elements.size).to eq(10)
668
- end
669
- end
670
-
671
- describe "#content" do
672
- it "should take String as default argument for type" do
673
- State.content :name
674
- address = Address.parse(fixture_file('address.xml'))
675
- expect(address.state.name).to eq("Lower Saxony")
676
- address.state.name.class == String
677
- end
678
-
679
- it "should work when specific type is provided" do
680
- Rate.content :value, Float
681
- Product.has_one :rate, Rate
682
- product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
683
- expect(product.rate.value).to eq(120.25)
684
- product.rate.class == Float
685
- end
686
- end
687
-
688
- it "should parse xml attributes into ruby objects" do
689
- posts = Post.parse(fixture_file('posts.xml'))
690
- expect(posts.size).to eq(20)
691
- first = posts.first
692
- expect(first.href).to eq('http://roxml.rubyforge.org/')
693
- expect(first.hash).to eq('19bba2ab667be03a19f67fb67dc56917')
694
- expect(first.description).to eq('ROXML - Ruby Object to XML Mapping Library')
695
- expect(first.tag).to eq('ruby xml gems mapping')
696
- expect(first.time).to eq(Time.utc(2008, 8, 9, 5, 24, 20))
697
- expect(first.others).to eq(56)
698
- expect(first.extended).to eq('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.')
699
- end
700
-
701
- it "should parse xml elements to ruby objcts" do
702
- statuses = Status.parse(fixture_file('statuses.xml'))
703
- expect(statuses.size).to eq(20)
704
- first = statuses.first
705
- expect(first.id).to eq(882281424)
706
- expect(first.created_at).to eq(Time.utc(2008, 8, 9, 5, 38, 12))
707
- expect(first.source).to eq('web')
708
- expect(first.truncated).to be_falsey
709
- expect(first.in_reply_to_status_id).to eq(1234)
710
- expect(first.in_reply_to_user_id).to eq(12345)
711
- expect(first.favorited).to be_falsey
712
- expect(first.user.id).to eq(4243)
713
- expect(first.user.name).to eq('John Nunemaker')
714
- expect(first.user.screen_name).to eq('jnunemaker')
715
- expect(first.user.location).to eq('Mishawaka, IN, US')
716
- expect(first.user.description).to eq('Loves his wife, ruby, notre dame football and iu basketball')
717
- expect(first.user.profile_image_url).to eq('http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg')
718
- expect(first.user.url).to eq('http://addictedtonew.com')
719
- expect(first.user.protected).to be_falsey
720
- expect(first.user.followers_count).to eq(486)
721
- end
722
-
723
- it "should parse xml containing the desired element as root node" do
724
- address = Address.parse(fixture_file('address.xml'), :single => true)
725
- expect(address.street).to eq('Milchstrasse')
726
- expect(address.postcode).to eq('26131')
727
- expect(address.housenumber).to eq('23')
728
- expect(address.city).to eq('Oldenburg')
729
- expect(address.country.class).to eq(Country)
730
- end
731
-
732
- it "should parse text node correctly" do
733
- address = Address.parse(fixture_file('address.xml'), :single => true)
734
- expect(address.country.name).to eq('Germany')
735
- expect(address.country.code).to eq('de')
736
- end
737
-
738
- it "should treat Nokogiri::XML::Document as root" do
739
- doc = Nokogiri::XML(fixture_file('address.xml'))
740
- address = Address.parse(doc)
741
- expect(address.class).to eq(Address)
742
- end
743
-
744
- it "should parse xml with default namespace (amazon)" do
745
- file_contents = fixture_file('pita.xml')
746
- items = PITA::Items.parse(file_contents, :single => true)
747
- expect(items.total_results).to eq(22)
748
- expect(items.total_pages).to eq(3)
749
- first = items.items[0]
750
- second = items.items[1]
751
- expect(first.asin).to eq('0321480791')
752
- expect(first.point).to eq('38.5351715088 -121.7948684692')
753
- expect(first.detail_page_url).to be_a_kind_of(URI)
754
- expect(first.detail_page_url.to_s).to eq('http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh')
755
- expect(first.manufacturer).to eq('Addison-Wesley Professional')
756
- expect(first.product_group).to eq('<ProductGroup>Book</ProductGroup>')
757
- expect(second.asin).to eq('047022388X')
758
- expect(second.manufacturer).to eq('Wrox')
759
- end
760
-
761
- it "should parse xml that has attributes of elements" do
762
- items = CurrentWeather.parse(fixture_file('current_weather.xml'))
763
- first = items[0]
764
- expect(first.temperature).to eq(51)
765
- expect(first.feels_like).to eq(51)
766
- expect(first.current_condition).to eq('Sunny')
767
- expect(first.current_condition.icon).to eq('http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif')
768
- end
769
-
770
- it "parses xml with attributes of elements that aren't :single => true" do
771
- feed = Atom::Feed.parse(fixture_file('atom.xml'))
772
- expect(feed.link.first.href).to eq('http://www.example.com')
773
- expect(feed.link.last.href).to eq('http://www.example.com/tv_shows.atom')
774
- end
775
-
776
- it "parses xml with optional elements with embedded attributes" do
777
- expect { CurrentWeather.parse(fixture_file('current_weather_missing_elements.xml')) }.to_not raise_error()
778
- end
779
-
780
- it "returns nil rather than empty array for absent values when :single => true" do
781
- address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true)
782
- expect(address).to be_nil
783
- end
784
-
785
- it "should return same result for absent values when :single => true, regardless of :in_groups_of" do
786
- addr1 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true)
787
- addr2 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true, :in_groups_of => 10)
788
- expect(addr1).to eq(addr2)
789
- end
790
-
791
- it "should parse xml with nested elements" do
792
- radars = Radar.parse(fixture_file('radar.xml'))
793
- first = radars[0]
794
- expect(first.places.size).to eq(1)
795
- expect(first.places[0].name).to eq('Store')
796
- second = radars[1]
797
- expect(second.places.size).to eq(0)
798
- third = radars[2]
799
- expect(third.places.size).to eq(2)
800
- expect(third.places[0].name).to eq('Work')
801
- expect(third.places[1].name).to eq('Home')
802
- end
803
-
804
- it "should parse xml with element name different to class name" do
805
- game = QuarterTest::Game.parse(fixture_file('quarters.xml'))
806
- expect(game.q1.start).to eq('4:40:15 PM')
807
- expect(game.q2.start).to eq('5:18:53 PM')
808
- end
809
-
810
- it "should parse xml that has elements with dashes" do
811
- commit = GitHub::Commit.parse(fixture_file('commit.xml'))
812
- expect(commit.message).to eq("move commands.rb and helpers.rb into commands/ dir")
813
- expect(commit.url).to eq("http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b")
814
- expect(commit.id).to eq("c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b")
815
- expect(commit.committed_date).to eq(Date.parse("2008-03-02T16:45:41-08:00"))
816
- expect(commit.tree).to eq("28a1a1ca3e663d35ba8bf07d3f1781af71359b76")
817
- end
818
-
819
- it "should parse xml with no namespace" do
820
- product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true)
821
- expect(product.title).to eq("A Title")
822
- expect(product.feature_bullets.bug).to eq('This is a bug')
823
- expect(product.feature_bullets.features.size).to eq(2)
824
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
825
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
826
- end
827
-
828
- it "should parse xml with default namespace" do
829
- product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
830
- expect(product.title).to eq("A Title")
831
- expect(product.feature_bullets.bug).to eq('This is a bug')
832
- expect(product.feature_bullets.features.size).to eq(2)
833
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
834
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
835
- end
836
-
837
- it "should parse xml with single namespace" do
838
- product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true)
839
- expect(product.title).to eq("A Title")
840
- expect(product.feature_bullets.bug).to eq('This is a bug')
841
- expect(product.feature_bullets.features.size).to eq(2)
842
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
843
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
844
- end
845
-
846
- it "should parse xml with multiple namespaces" do
847
- track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
848
- expect(track.highest_severity).to eq('SUCCESS')
849
- expect(track.more_data).to be_falsey
850
- notification = track.notifications.first
851
- expect(notification.code).to eq(0)
852
- expect(notification.localized_message).to eq('Request was successfully processed.')
853
- expect(notification.message).to eq('Request was successfully processed.')
854
- expect(notification.severity).to eq('SUCCESS')
855
- expect(notification.source).to eq('trck')
856
- detail = track.trackdetails.first
857
- expect(detail.carrier_code).to eq('FDXG')
858
- expect(detail.est_delivery).to eq('2009-01-02T00:00:00')
859
- expect(detail.service_info).to eq('Ground-Package Returns Program-Domestic')
860
- expect(detail.status_code).to eq('OD')
861
- expect(detail.status_desc).to eq('On FedEx vehicle for delivery')
862
- expect(detail.tracking_number).to eq('9611018034267800045212')
863
- expect(detail.weight.units).to eq('LB')
864
- expect(detail.weight.value).to eq(2)
865
- events = detail.events
866
- expect(events.size).to eq(10)
867
- first_event = events[0]
868
- expect(first_event.eventdescription).to eq('On FedEx vehicle for delivery')
869
- expect(first_event.eventtype).to eq('OD')
870
- expect(first_event.timestamp).to eq('2009-01-02T06:00:00')
871
- expect(first_event.address.city).to eq('WICHITA')
872
- expect(first_event.address.countrycode).to eq('US')
873
- expect(first_event.address.residential).to be_falsey
874
- expect(first_event.address.state).to eq('KS')
875
- expect(first_event.address.zip).to eq('67226')
876
- last_event = events[-1]
877
- expect(last_event.eventdescription).to eq('In FedEx possession')
878
- expect(last_event.eventtype).to eq('IP')
879
- expect(last_event.timestamp).to eq('2008-12-27T09:40:00')
880
- expect(last_event.address.city).to eq('LONGWOOD')
881
- expect(last_event.address.countrycode).to eq('US')
882
- expect(last_event.address.residential).to be_falsey
883
- expect(last_event.address.state).to eq('FL')
884
- expect(last_event.address.zip).to eq('327506398')
885
- expect(track.tran_detail.cust_tran_id).to eq('20090102-111321')
886
- end
887
-
888
- it "should be able to parse google analytics api xml" do
889
- data = Analytics::Feed.parse(fixture_file('analytics.xml'))
890
- expect(data.id).to eq('http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com')
891
- expect(data.entries.size).to eq(4)
892
-
893
- entry = data.entries[0]
894
- expect(entry.title).to eq('addictedtonew.com')
895
- expect(entry.properties.size).to eq(4)
896
-
897
- property = entry.properties[0]
898
- expect(property.name).to eq('ga:accountId')
899
- expect(property.value).to eq('85301')
900
- end
901
-
902
- it "should be able to parse google analytics profile xml with manually declared namespace" do
903
- data = Analytics::Profile.parse(fixture_file('analytics_profile.xml'))
904
- expect(data.entries.size).to eq(6)
905
-
906
- entry = data.entries[0]
907
- expect(entry.title).to eq('www.homedepot.com')
908
- expect(entry.properties.size).to eq(6)
909
- expect(entry.goals.size).to eq(0)
910
- end
911
-
912
- it "should allow instantiating with a string" do
913
- module StringFoo
914
- class Bar
915
- include HappyMapper
916
- has_many :things, 'StringFoo::Thing'
917
- end
918
-
919
- class Thing
920
- include HappyMapper
921
- end
922
- end
923
- end
924
-
925
- it "should parse family search xml" do
926
- tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
927
- expect(tree.version).to eq('1.0.20071213.942')
928
- expect(tree.status_message).to eq('OK')
929
- expect(tree.status_code).to eq('200')
930
- expect(tree.persons.person.size).to eq(1)
931
- expect(tree.persons.person.first.version).to eq('1199378491000')
932
- expect(tree.persons.person.first.modified).to eq(Time.utc(2008, 1, 3, 16, 41, 31)) # 2008-01-03T09:41:31-07:00
933
- expect(tree.persons.person.first.id).to eq('KWQS-BBQ')
934
- expect(tree.persons.person.first.information.alternateIds.ids).not_to be_kind_of(String)
935
- expect(tree.persons.person.first.information.alternateIds.ids.size).to eq(8)
936
- end
937
-
938
- it "should parse multiple images" do
939
- artist = Artist.parse(fixture_file('multiple_primitives.xml'))
940
- expect(artist.name).to eq("value")
941
- expect(artist.images.size).to eq(2)
942
- end
943
-
944
- it "should parse lastfm namespaces" do
945
- l = Location.parse(fixture_file('lastfm.xml'))
946
- expect(l.first.latitude).to eq("51.53469")
947
- end
948
-
949
- describe "Parse optional attributes" do
950
-
951
- it "should parse an empty String as empty" do
952
- a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
953
- expect(a[0].street).to eq("")
954
- end
955
-
956
- it "should parse a String with value" do
957
- a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
958
- expect(a[1].street).to eq("Milchstrasse")
959
- end
960
-
961
- it "should parse a String with value" do
962
- a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
963
- expect(a[2].street).to be_nil
964
- end
965
-
966
- end
967
-
968
- describe "Default namespace combi" do
969
- before(:each) do
970
- file_contents = fixture_file('default_namespace_combi.xml')
971
- @book = DefaultNamespaceCombi.parse(file_contents, :single => true)
972
- end
973
-
974
- it "should parse author" do
975
- expect(@book.author).to eq("Frank Gilbreth")
976
- end
977
-
978
- it "should parse title" do
979
- expect(@book.title).to eq("Cheaper by the Dozen")
980
- end
981
-
982
- it "should parse number" do
983
- expect(@book.number).to eq("1568491379")
984
- end
985
-
986
- end
987
-
988
- describe 'Xml Content' do
989
- before(:each) do
990
- file_contents = fixture_file('dictionary.xml')
991
- @records = Dictionary::Record.parse(file_contents)
992
- end
993
-
994
- it "should parse XmlContent" do
995
- expect(@records.first.definitions.first.text).to eq(
996
- 'a large common parrot, <bn>Cacatua galerita</bn>, predominantly white, with yellow on the undersides of wings and tail and a forward curving yellow crest, found in Australia, New Guinea and nearby islands.'
997
- )
998
- end
999
-
1000
- it "should save object's xml content" do
1001
- expect(@records.first.variants.first.xml_content).to eq(
1002
- 'white <tag>cockatoo</tag>'
1003
- )
1004
- expect(@records.first.variants.last.to_html).to eq(
1005
- '<em>white</em> cockatoo'
1006
- )
1007
- end
1008
- end
1009
-
1010
- it "should parse ambigous items" do
1011
- items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), :xpath => '/ambigous/my-items')
1012
- expect(items.map(&:name)).to eq(%w(first second third).map{|s| "My #{s} item" })
1013
- end
1014
-
1015
-
1016
- context Article do
1017
- it "should parse the publish options for Article and Photo" do
1018
- expect(@article.title).not_to be_nil
1019
- expect(@article.text).not_to be_nil
1020
- expect(@article.photos).not_to be_nil
1021
- expect(@article.photos.first.title).not_to be_nil
1022
- end
1023
-
1024
- it "should parse the publish options for Article" do
1025
- expect(@article.publish_options).not_to be_nil
1026
- end
1027
-
1028
- it "should parse the publish options for Photo" do
1029
- expect(@article.photos.first.publish_options).not_to be_nil
1030
- end
1031
-
1032
- it "should only find only items at the parent level" do
1033
- expect(@article.photos.length).to eq(1)
1034
- end
1035
-
1036
- before(:all) do
1037
- @article = Article.parse(fixture_file('subclass_namespace.xml'))
1038
- end
1039
-
1040
- end
1041
-
1042
- context "Namespace is missing because an optional element that uses it is not present" do
1043
- it "should parse successfully" do
1044
- @article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
1045
- expect(@article).not_to be_nil
1046
- expect(@article.title).not_to be_nil
1047
- expect(@article.text).not_to be_nil
1048
- expect(@article.photos).not_to be_nil
1049
- expect(@article.photos.first.title).not_to be_nil
1050
- end
1051
- end
1052
-
1053
-
1054
- describe "with limit option" do
1055
- it "should return results with limited size: 6" do
1056
- sizes = []
1057
- Post.parse(fixture_file('posts.xml'), :in_groups_of => 6) do |a|
1058
- sizes << a.size
1059
- end
1060
- expect(sizes).to eq([6, 6, 6, 2])
1061
- end
1062
-
1063
- it "should return results with limited size: 10" do
1064
- sizes = []
1065
- Post.parse(fixture_file('posts.xml'), :in_groups_of => 10) do |a|
1066
- sizes << a.size
1067
- end
1068
- expect(sizes).to eq([10, 10])
1069
- end
1070
- end
1071
-
1072
- context "when letting user set Nokogiri::XML::ParseOptions" do
1073
- let(:default) {
1074
- Class.new do
1075
- include HappyMapper
1076
- element :item, String
1077
- end
1078
- }
1079
- let(:custom) {
1080
- Class.new do
1081
- include HappyMapper
1082
- element :item, String
1083
- with_nokogiri_config do |config|
1084
- config.default_xml
1085
- end
1086
- end
1087
- }
1088
-
1089
- it 'initializes @nokogiri_config_callback to nil' do
1090
- expect(default.nokogiri_config_callback).to be_nil
1091
- end
1092
-
1093
- it 'defaults to Nokogiri::XML::ParseOptions::STRICT' do
1094
- expect { default.parse(fixture_file('set_config_options.xml')) }.to raise_error(Nokogiri::XML::SyntaxError)
1095
- end
1096
-
1097
- it 'accepts .on_config callback' do
1098
- expect(custom.nokogiri_config_callback).not_to be_nil
1099
- end
1100
-
1101
- it 'parses according to @nokogiri_config_callback' do
1102
- expect { custom.parse(fixture_file('set_config_options.xml')) }.to_not raise_error
1103
- end
1104
-
1105
- it 'can clear @nokogiri_config_callback' do
1106
- custom.with_nokogiri_config {}
1107
- expect { custom.parse(fixture_file('set_config_options.xml')) }.to raise_error(Nokogiri::XML::SyntaxError)
1108
- end
1109
- end
1110
-
1111
- context 'xml_value' do
1112
- it 'does not reformat the xml' do
1113
- xml = fixture_file('unformatted_address.xml')
1114
- address = Address.parse(xml, single: true)
1115
-
1116
- expect(address.xml_value).to eq %{<address><street>Milchstrasse</street><housenumber>23</housenumber></address>}
1117
- end
1118
- end
1119
-
1120
- context 'xml_content' do
1121
- it 'does not reformat the xml' do
1122
- xml = fixture_file('unformatted_address.xml')
1123
- address = Address.parse(xml)
1124
-
1125
- expect(address.xml_content).to eq %{<street>Milchstrasse</street><housenumber>23</housenumber>}
1126
- end
1127
- end
1128
-
1129
- end