nokogiri-happymapper 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +0 -3
  4. data/lib/happymapper/element.rb +2 -2
  5. data/lib/happymapper/supported_types.rb +3 -5
  6. data/lib/happymapper/version.rb +1 -1
  7. data/lib/happymapper.rb +44 -52
  8. metadata +98 -107
  9. data/spec/features/after_parse_callbacks_spec.rb +0 -32
  10. data/spec/features/attribute_default_value_spec.rb +0 -48
  11. data/spec/features/attributes_spec.rb +0 -35
  12. data/spec/features/has_many_empty_array_spec.rb +0 -44
  13. data/spec/features/ignay_spec.rb +0 -92
  14. data/spec/features/inheritance_spec.rb +0 -121
  15. data/spec/features/mixed_namespaces_spec.rb +0 -60
  16. data/spec/features/parse_with_object_to_update_spec.rb +0 -116
  17. data/spec/features/same_tag_different_meaning_spec.rb +0 -44
  18. data/spec/features/to_xml_spec.rb +0 -205
  19. data/spec/features/to_xml_with_namespaces_spec.rb +0 -237
  20. data/spec/features/wildcard_tag_name_spec.rb +0 -110
  21. data/spec/features/wrap_spec.rb +0 -87
  22. data/spec/features/xpath_spec.rb +0 -84
  23. data/spec/fixtures/address.xml +0 -9
  24. data/spec/fixtures/ambigous_items.xml +0 -22
  25. data/spec/fixtures/analytics.xml +0 -61
  26. data/spec/fixtures/analytics_profile.xml +0 -127
  27. data/spec/fixtures/atom.xml +0 -19
  28. data/spec/fixtures/commit.xml +0 -52
  29. data/spec/fixtures/current_weather.xml +0 -89
  30. data/spec/fixtures/current_weather_missing_elements.xml +0 -18
  31. data/spec/fixtures/default_namespace_combi.xml +0 -6
  32. data/spec/fixtures/dictionary.xml +0 -20
  33. data/spec/fixtures/family_tree.xml +0 -21
  34. data/spec/fixtures/inagy.xml +0 -85
  35. data/spec/fixtures/lastfm.xml +0 -355
  36. data/spec/fixtures/multiple_namespaces.xml +0 -170
  37. data/spec/fixtures/multiple_primitives.xml +0 -5
  38. data/spec/fixtures/optional_attributes.xml +0 -6
  39. data/spec/fixtures/pita.xml +0 -133
  40. data/spec/fixtures/posts.xml +0 -23
  41. data/spec/fixtures/product_default_namespace.xml +0 -18
  42. data/spec/fixtures/product_no_namespace.xml +0 -10
  43. data/spec/fixtures/product_single_namespace.xml +0 -10
  44. data/spec/fixtures/quarters.xml +0 -19
  45. data/spec/fixtures/radar.xml +0 -21
  46. data/spec/fixtures/set_config_options.xml +0 -3
  47. data/spec/fixtures/statuses.xml +0 -422
  48. data/spec/fixtures/subclass_namespace.xml +0 -50
  49. data/spec/fixtures/unformatted_address.xml +0 -1
  50. data/spec/fixtures/wrapper.xml +0 -11
  51. data/spec/happymapper/anonymous_mapper_spec.rb +0 -158
  52. data/spec/happymapper/attribute_spec.rb +0 -12
  53. data/spec/happymapper/item_spec.rb +0 -177
  54. data/spec/happymapper_spec.rb +0 -1208
  55. data/spec/spec_helper.rb +0 -25
@@ -1,1208 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
- require 'uri'
5
-
6
- module Analytics
7
- class Property
8
- include HappyMapper
9
-
10
- tag 'property'
11
- namespace 'dxp'
12
- attribute :name, String
13
- attribute :value, String
14
- end
15
-
16
- class Goal
17
- include HappyMapper
18
-
19
- # Google Analytics does a dirtry trick where a user with no goals
20
- # returns a profile without any goals data or the declared namespace
21
- # which means Nokogiri does not pick up the namespace automatically.
22
- # To fix this, we manually register the namespace to avoid bad XPath
23
- # expression. Dirty, but works.
24
-
25
- register_namespace 'ga', 'http://schemas.google.com/ga/2009'
26
- namespace 'ga'
27
-
28
- tag 'goal'
29
- attribute :active, Boolean
30
- attribute :name, String
31
- attribute :number, Integer
32
- attribute :value, Float
33
-
34
- def clean_name
35
- name.gsub(/ga:/, '')
36
- end
37
- end
38
-
39
- class Profile
40
- include HappyMapper
41
-
42
- tag 'entry'
43
- element :title, String
44
- element :tableId, String, namespace: 'dxp'
45
-
46
- has_many :properties, Property
47
- has_many :goals, Goal
48
- end
49
-
50
- class Entry
51
- include HappyMapper
52
-
53
- tag 'entry'
54
- element :id, String
55
- element :updated, DateTime
56
- element :title, String
57
- element :table_id, String, namespace: 'dxp', tag: 'tableId'
58
- has_many :properties, Property
59
- end
60
-
61
- class Feed
62
- include HappyMapper
63
-
64
- tag 'feed'
65
- element :id, String
66
- element :updated, DateTime
67
- element :title, String
68
- has_many :entries, Entry
69
- end
70
- end
71
-
72
- module Atom
73
- class Feed
74
- include HappyMapper
75
- tag 'feed'
76
-
77
- attribute :xmlns, String, single: true
78
- element :id, String, single: true
79
- element :title, String, single: true
80
- element :updated, DateTime, single: true
81
- element :link, String, single: false, attributes: {
82
- rel: String,
83
- type: String,
84
- href: String
85
- }
86
- # has_many :entries, Entry # nothing interesting in the entries
87
- end
88
- end
89
-
90
- class Country
91
- include HappyMapper
92
-
93
- attribute :code, String
94
- content :name, String
95
- end
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
- end
462
-
463
- class Article
464
- include HappyMapper
465
-
466
- tag 'Article'
467
- namespace 'article'
468
-
469
- attr_writer :xml_value
470
-
471
- element :title, String
472
- element :text, String
473
- has_many :photos, 'Photo', tag: 'Photo', namespace: 'photo', xpath: '/article:Article'
474
- has_many :galleries, 'Gallery', tag: 'Gallery', namespace: 'gallery'
475
-
476
- element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'article'
477
- end
478
-
479
- class PartiallyBadArticle
480
- include HappyMapper
481
-
482
- attr_writer :xml_value
483
-
484
- tag 'Article'
485
- namespace 'article'
486
-
487
- element :title, String
488
- element :text, String
489
- has_many :photos, 'Photo', tag: 'Photo', namespace: 'photo', xpath: '/article:Article'
490
- has_many :videos, 'Video', tag: 'Video', namespace: 'video'
491
-
492
- element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'article'
493
- end
494
-
495
- class Photo
496
- include HappyMapper
497
-
498
- tag 'Photo'
499
- namespace 'photo'
500
-
501
- attr_writer :xml_value
502
-
503
- element :title, String
504
- element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'photo'
505
- end
506
-
507
- class Gallery
508
- include HappyMapper
509
-
510
- tag 'Gallery'
511
- namespace 'gallery'
512
-
513
- attr_writer :xml_value
514
-
515
- element :title, String
516
- end
517
-
518
- class Video
519
- include HappyMapper
520
-
521
- tag 'Video'
522
- namespace 'video'
523
-
524
- attr_writer :xml_value
525
-
526
- element :title, String
527
- element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'video'
528
- end
529
-
530
- class OptionalAttribute
531
- include HappyMapper
532
- tag 'address'
533
-
534
- attribute :street, String
535
- end
536
-
537
- class DefaultNamespaceCombi
538
- include HappyMapper
539
-
540
- register_namespace 'bk', 'urn:loc.gov:books'
541
- register_namespace 'isbn', 'urn:ISBN:0-395-36341-6'
542
- register_namespace 'p', 'urn:loc.gov:people'
543
- namespace 'bk'
544
-
545
- tag 'book'
546
-
547
- element :title, String, namespace: 'bk', tag: 'title'
548
- element :number, String, namespace: 'isbn', tag: 'number'
549
- element :author, String, namespace: 'p', tag: 'author'
550
- end
551
-
552
- describe HappyMapper do
553
- describe 'being included into another class' do
554
- let(:klass) do
555
- Class.new do
556
- include HappyMapper
557
-
558
- def self.name
559
- 'Boo'
560
- end
561
- end
562
- end
563
-
564
- it 'sets attributes to an array' do
565
- expect(klass.attributes).to eq([])
566
- end
567
-
568
- it 'sets @elements to a hash' do
569
- expect(klass.elements).to eq([])
570
- end
571
-
572
- it 'allows adding an attribute' do
573
- expect do
574
- klass.attribute :name, String
575
- end.to change(klass, :attributes)
576
- end
577
-
578
- it 'allows adding an attribute containing a dash' do
579
- expect do
580
- klass.attribute :'bar-baz', String
581
- end.to change(klass, :attributes)
582
- end
583
-
584
- it 'is able to get all attributes in array' do
585
- klass.attribute :name, String
586
- expect(klass.attributes.size).to eq(1)
587
- end
588
-
589
- it 'allows adding an element' do
590
- expect do
591
- klass.element :name, String
592
- end.to change(klass, :elements)
593
- end
594
-
595
- it 'allows adding an element containing a dash' do
596
- expect do
597
- klass.element :'bar-baz', String
598
- end.to change(klass, :elements)
599
- end
600
-
601
- it 'is able to get all elements in array' do
602
- klass.element(:name, String)
603
- expect(klass.elements.size).to eq(1)
604
- end
605
-
606
- it 'allows has one association' do
607
- klass.has_one(:user, User)
608
- element = klass.elements.first
609
-
610
- aggregate_failures do
611
- expect(element.name).to eq('user')
612
- expect(element.type).to eq(User)
613
- expect(element.options[:single]).to eq(true)
614
- end
615
- end
616
-
617
- it 'allows has many association' do
618
- klass.has_many(:users, User)
619
- element = klass.elements.first
620
-
621
- aggregate_failures do
622
- expect(element.name).to eq('users')
623
- expect(element.type).to eq(User)
624
- expect(element.options[:single]).to eq(false)
625
- end
626
- end
627
-
628
- it 'defaults tag name to lowercase class' do
629
- expect(klass.tag_name).to eq('boo')
630
- end
631
-
632
- it 'generates no tag name for anonymous class' do
633
- @anon = Class.new { include HappyMapper }
634
- expect(@anon.tag_name).to be_nil
635
- end
636
-
637
- it 'defaults 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 'allows setting tag name' do
643
- klass.tag('FooBar')
644
- expect(klass.tag_name).to eq('FooBar')
645
- end
646
-
647
- it 'allows setting a namespace' do
648
- klass.namespace(namespace = 'boo')
649
- expect(klass.namespace).to eq(namespace)
650
- end
651
-
652
- it 'provides #parse' do
653
- expect(klass).to respond_to(:parse)
654
- end
655
- end
656
-
657
- describe '#attributes' do
658
- it 'returns only attributes for the current class' do
659
- aggregate_failures do
660
- expect(Post.attributes.size).to eq(7)
661
- expect(Status.attributes.size).to eq(0)
662
- end
663
- end
664
- end
665
-
666
- describe '#elements' do
667
- it 'returns only elements for the current class' do
668
- aggregate_failures do
669
- expect(Post.elements.size).to eq(0)
670
- expect(Status.elements.size).to eq(10)
671
- end
672
- end
673
- end
674
-
675
- describe '#content' do
676
- it 'takes String as default argument for type' do
677
- State.content :name
678
- address = Address.parse(fixture_file('address.xml'))
679
- name = address.state.name
680
-
681
- aggregate_failures do
682
- expect(name).to eq 'Lower Saxony'
683
- expect(name).to be_a String
684
- end
685
- end
686
-
687
- it 'works when specific type is provided' do
688
- Rate.content :value, Float
689
- Product.has_one :rate, Rate
690
- product = Product.parse(fixture_file('product_default_namespace.xml'), single: true)
691
- value = product.rate.value
692
-
693
- aggregate_failures do
694
- expect(value).to eq(120.25)
695
- expect(value).to be_a Float
696
- end
697
- end
698
- end
699
-
700
- it 'parses xml attributes into ruby objects' do
701
- posts = Post.parse(fixture_file('posts.xml'))
702
-
703
- aggregate_failures do
704
- expect(posts.size).to eq(20)
705
- first = posts.first
706
- expect(first.href).to eq('http://roxml.rubyforge.org/')
707
- expect(first.hash).to eq('19bba2ab667be03a19f67fb67dc56917')
708
- expect(first.description).to eq('ROXML - Ruby Object to XML Mapping Library')
709
- expect(first.tag).to eq('ruby xml gems mapping')
710
- expect(first.time).to eq(Time.utc(2008, 8, 9, 5, 24, 20))
711
- expect(first.others).to eq(56)
712
- expect(first.extended).
713
- to eq('ROXML is a Ruby library designed to make it easier for Ruby' \
714
- ' developers to work with XML. Using simple annotations, it enables' \
715
- ' Ruby classes to be custom-mapped to XML. ROXML takes care of the' \
716
- ' marshalling and unmarshalling of mapped attributes so that developers can' \
717
- ' focus on building first-class Ruby classes.')
718
- end
719
- end
720
-
721
- it 'parses xml elements to ruby objcts' do
722
- statuses = Status.parse(fixture_file('statuses.xml'))
723
-
724
- aggregate_failures do
725
- expect(statuses.size).to eq(20)
726
- first = statuses.first
727
- expect(first.id).to eq(882_281_424)
728
- expect(first.created_at).to eq(Time.utc(2008, 8, 9, 5, 38, 12))
729
- expect(first.source).to eq('web')
730
- expect(first.truncated).to be_falsey
731
- expect(first.in_reply_to_status_id).to eq(1234)
732
- expect(first.in_reply_to_user_id).to eq(12_345)
733
- expect(first.favorited).to be_falsey
734
- expect(first.user.id).to eq(4243)
735
- expect(first.user.name).to eq('John Nunemaker')
736
- expect(first.user.screen_name).to eq('jnunemaker')
737
- expect(first.user.location).to eq('Mishawaka, IN, US')
738
- expect(first.user.description).to eq('Loves his wife, ruby, notre dame football and iu basketball')
739
- expect(first.user.profile_image_url).
740
- to eq('http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg')
741
- expect(first.user.url).to eq('http://addictedtonew.com')
742
- expect(first.user.protected).to be_falsey
743
- expect(first.user.followers_count).to eq(486)
744
- end
745
- end
746
-
747
- it 'parses xml containing the desired element as root node' do
748
- address = Address.parse(fixture_file('address.xml'), single: true)
749
-
750
- aggregate_failures do
751
- expect(address.street).to eq('Milchstrasse')
752
- expect(address.postcode).to eq('26131')
753
- expect(address.housenumber).to eq('23')
754
- expect(address.city).to eq('Oldenburg')
755
- expect(address.country.class).to eq(Country)
756
- end
757
- end
758
-
759
- it 'parses text node correctly' do
760
- address = Address.parse(fixture_file('address.xml'), single: true)
761
-
762
- aggregate_failures do
763
- expect(address.country.name).to eq('Germany')
764
- expect(address.country.code).to eq('de')
765
- end
766
- end
767
-
768
- it 'treats Nokogiri::XML::Document as root' do
769
- doc = Nokogiri::XML(fixture_file('address.xml'))
770
- address = Address.parse(doc)
771
- expect(address.class).to eq(Address)
772
- end
773
-
774
- it 'parses xml with default namespace (amazon)' do
775
- file_contents = fixture_file('pita.xml')
776
- items = PITA::Items.parse(file_contents, single: true)
777
-
778
- aggregate_failures do
779
- expect(items.total_results).to eq(22)
780
- expect(items.total_pages).to eq(3)
781
-
782
- first = items.items[0]
783
-
784
- expect(first.asin).to eq('0321480791')
785
- expect(first.point).to eq('38.5351715088 -121.7948684692')
786
- expect(first.detail_page_url).to be_a_kind_of(URI)
787
- 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')
788
- expect(first.manufacturer).to eq('Addison-Wesley Professional')
789
- expect(first.product_group).to eq('<ProductGroup>Book</ProductGroup>')
790
-
791
- second = items.items[1]
792
-
793
- expect(second.asin).to eq('047022388X')
794
- expect(second.manufacturer).to eq('Wrox')
795
- end
796
- end
797
-
798
- it 'parses xml that has attributes of elements' do
799
- items = CurrentWeather.parse(fixture_file('current_weather.xml'))
800
- first = items[0]
801
-
802
- aggregate_failures do
803
- expect(first.temperature).to eq(51)
804
- expect(first.feels_like).to eq(51)
805
- expect(first.current_condition).to eq('Sunny')
806
- expect(first.current_condition.icon).to eq('http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif')
807
- end
808
- end
809
-
810
- it "parses xml with attributes of elements that aren't :single => true" do
811
- feed = Atom::Feed.parse(fixture_file('atom.xml'))
812
-
813
- aggregate_failures do
814
- expect(feed.link.first.href).to eq('http://www.example.com')
815
- expect(feed.link.last.href).to eq('http://www.example.com/tv_shows.atom')
816
- end
817
- end
818
-
819
- it 'parses xml with optional elements with embedded attributes' do
820
- expect { CurrentWeather.parse(fixture_file('current_weather_missing_elements.xml')) }.not_to raise_error
821
- end
822
-
823
- it 'returns nil rather than empty array for absent values when :single => true' do
824
- address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true)
825
- expect(address).to be_nil
826
- end
827
-
828
- it 'returns same result for absent values when :single => true, regardless of :in_groups_of' do
829
- addr1 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true)
830
- addr2 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true, in_groups_of: 10)
831
- expect(addr1).to eq(addr2)
832
- end
833
-
834
- it 'parses xml with nested elements' do
835
- radars = Radar.parse(fixture_file('radar.xml'))
836
-
837
- aggregate_failures do
838
- first = radars[0]
839
- expect(first.places.size).to eq(1)
840
- expect(first.places[0].name).to eq('Store')
841
- second = radars[1]
842
- expect(second.places.size).to eq(0)
843
- third = radars[2]
844
- expect(third.places.size).to eq(2)
845
- expect(third.places[0].name).to eq('Work')
846
- expect(third.places[1].name).to eq('Home')
847
- end
848
- end
849
-
850
- it 'parses xml with element name different to class name' do
851
- game = QuarterTest::Game.parse(fixture_file('quarters.xml'))
852
-
853
- aggregate_failures do
854
- expect(game.q1.start).to eq('4:40:15 PM')
855
- expect(game.q2.start).to eq('5:18:53 PM')
856
- end
857
- end
858
-
859
- it 'parses xml that has elements with dashes' do
860
- commit = GitHub::Commit.parse(fixture_file('commit.xml'))
861
-
862
- aggregate_failures do
863
- expect(commit.message).to eq('move commands.rb and helpers.rb into commands/ dir')
864
- expect(commit.url).to eq('http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b')
865
- expect(commit.id).to eq('c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b')
866
- expect(commit.committed_date).to eq(Date.parse('2008-03-02T16:45:41-08:00'))
867
- expect(commit.tree).to eq('28a1a1ca3e663d35ba8bf07d3f1781af71359b76')
868
- end
869
- end
870
-
871
- it 'parses xml with no namespace' do
872
- product = Product.parse(fixture_file('product_no_namespace.xml'), single: true)
873
-
874
- aggregate_failures do
875
- expect(product.title).to eq('A Title')
876
- expect(product.feature_bullets.bug).to eq('This is a bug')
877
- expect(product.feature_bullets.features.size).to eq(2)
878
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
879
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
880
- end
881
- end
882
-
883
- it 'parses xml with default namespace' do
884
- product = Product.parse(fixture_file('product_default_namespace.xml'), single: true)
885
-
886
- aggregate_failures do
887
- expect(product.title).to eq('A Title')
888
- expect(product.feature_bullets.bug).to eq('This is a bug')
889
- expect(product.feature_bullets.features.size).to eq(2)
890
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
891
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
892
- end
893
- end
894
-
895
- it 'parses xml with single namespace' do
896
- product = Product.parse(fixture_file('product_single_namespace.xml'), single: true)
897
-
898
- aggregate_failures do
899
- expect(product.title).to eq('A Title')
900
- expect(product.feature_bullets.bug).to eq('This is a bug')
901
- expect(product.feature_bullets.features.size).to eq(2)
902
- expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
903
- expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
904
- end
905
- end
906
-
907
- it 'parses xml with multiple namespaces' do
908
- track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
909
-
910
- aggregate_failures do
911
- expect(track.highest_severity).to eq('SUCCESS')
912
- expect(track.more_data).to be_falsey
913
- notification = track.notifications.first
914
- expect(notification.code).to eq(0)
915
- expect(notification.localized_message).to eq('Request was successfully processed.')
916
- expect(notification.message).to eq('Request was successfully processed.')
917
- expect(notification.severity).to eq('SUCCESS')
918
- expect(notification.source).to eq('trck')
919
- detail = track.trackdetails.first
920
- expect(detail.carrier_code).to eq('FDXG')
921
- expect(detail.est_delivery).to eq('2009-01-02T00:00:00')
922
- expect(detail.service_info).to eq('Ground-Package Returns Program-Domestic')
923
- expect(detail.status_code).to eq('OD')
924
- expect(detail.status_desc).to eq('On FedEx vehicle for delivery')
925
- expect(detail.tracking_number).to eq('9611018034267800045212')
926
- expect(detail.weight.units).to eq('LB')
927
- expect(detail.weight.value).to eq(2)
928
- events = detail.events
929
- expect(events.size).to eq(10)
930
- first_event = events[0]
931
- expect(first_event.eventdescription).to eq('On FedEx vehicle for delivery')
932
- expect(first_event.eventtype).to eq('OD')
933
- expect(first_event.timestamp).to eq('2009-01-02T06:00:00')
934
- expect(first_event.address.city).to eq('WICHITA')
935
- expect(first_event.address.countrycode).to eq('US')
936
- expect(first_event.address.residential).to be_falsey
937
- expect(first_event.address.state).to eq('KS')
938
- expect(first_event.address.zip).to eq('67226')
939
- last_event = events[-1]
940
- expect(last_event.eventdescription).to eq('In FedEx possession')
941
- expect(last_event.eventtype).to eq('IP')
942
- expect(last_event.timestamp).to eq('2008-12-27T09:40:00')
943
- expect(last_event.address.city).to eq('LONGWOOD')
944
- expect(last_event.address.countrycode).to eq('US')
945
- expect(last_event.address.residential).to be_falsey
946
- expect(last_event.address.state).to eq('FL')
947
- expect(last_event.address.zip).to eq('327506398')
948
- expect(track.tran_detail.cust_tran_id).to eq('20090102-111321')
949
- end
950
- end
951
-
952
- it 'is able to parse google analytics api xml' do
953
- data = Analytics::Feed.parse(fixture_file('analytics.xml'))
954
-
955
- aggregate_failures do
956
- expect(data.id).to eq('http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com')
957
- expect(data.entries.size).to eq(4)
958
-
959
- entry = data.entries[0]
960
- expect(entry.title).to eq('addictedtonew.com')
961
- expect(entry.properties.size).to eq(4)
962
-
963
- property = entry.properties[0]
964
- expect(property.name).to eq('ga:accountId')
965
- expect(property.value).to eq('85301')
966
- end
967
- end
968
-
969
- it 'is able to parse google analytics profile xml with manually declared namespace' do
970
- data = Analytics::Profile.parse(fixture_file('analytics_profile.xml'))
971
-
972
- aggregate_failures do
973
- expect(data.entries.size).to eq(6)
974
- entry = data.entries[0]
975
- expect(entry.title).to eq('www.homedepot.com')
976
- expect(entry.properties.size).to eq(6)
977
- expect(entry.goals.size).to eq(0)
978
- end
979
- end
980
-
981
- it 'allows instantiating with a string' do
982
- module StringFoo
983
- class Bar
984
- include HappyMapper
985
- has_many :things, 'StringFoo::Thing'
986
- end
987
-
988
- class Thing
989
- include HappyMapper
990
- end
991
- end
992
- end
993
-
994
- it 'parses family search xml' do
995
- tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
996
-
997
- aggregate_failures do
998
- expect(tree.version).to eq('1.0.20071213.942')
999
- expect(tree.status_message).to eq('OK')
1000
- expect(tree.status_code).to eq('200')
1001
- expect(tree.persons.person.size).to eq(1)
1002
- expect(tree.persons.person.first.version).to eq('1199378491000')
1003
- expect(tree.persons.person.first.modified).
1004
- to eq(Time.utc(2008, 1, 3, 16, 41, 31)) # 2008-01-03T09:41:31-07:00
1005
- expect(tree.persons.person.first.id).to eq('KWQS-BBQ')
1006
- expect(tree.persons.person.first.information.alternateIds.ids).not_to be_kind_of(String)
1007
- expect(tree.persons.person.first.information.alternateIds.ids.size).to eq(8)
1008
- end
1009
- end
1010
-
1011
- it 'parses multiple images' do
1012
- artist = Artist.parse(fixture_file('multiple_primitives.xml'))
1013
-
1014
- aggregate_failures do
1015
- expect(artist.name).to eq('value')
1016
- expect(artist.images.size).to eq(2)
1017
- end
1018
- end
1019
-
1020
- it 'parses lastfm namespaces' do
1021
- l = Location.parse(fixture_file('lastfm.xml'))
1022
- expect(l.first.latitude).to eq('51.53469')
1023
- end
1024
-
1025
- describe 'Parse optional attributes' do
1026
- let(:parsed_result) { OptionalAttribute.parse(fixture_file('optional_attributes.xml')) }
1027
-
1028
- it 'parses an empty String as empty' do
1029
- expect(parsed_result[0].street).to eq('')
1030
- end
1031
-
1032
- it 'parses a String with value' do
1033
- expect(parsed_result[1].street).to eq('Milchstrasse')
1034
- end
1035
-
1036
- it 'parses an element with no value for the attribute' do
1037
- expect(parsed_result[2].street).to be_nil
1038
- end
1039
- end
1040
-
1041
- describe 'Default namespace combi' do
1042
- let(:file_contents) { fixture_file('default_namespace_combi.xml') }
1043
- let(:book) { DefaultNamespaceCombi.parse(file_contents, single: true) }
1044
-
1045
- it 'parses author' do
1046
- expect(book.author).to eq('Frank Gilbreth')
1047
- end
1048
-
1049
- it 'parses title' do
1050
- expect(book.title).to eq('Cheaper by the Dozen')
1051
- end
1052
-
1053
- it 'parses number' do
1054
- expect(book.number).to eq('1568491379')
1055
- end
1056
- end
1057
-
1058
- describe 'Xml Content' do
1059
- let(:records) { Dictionary::Record.parse fixture_file('dictionary.xml') }
1060
-
1061
- it 'parses XmlContent' do
1062
- expect(records.first.definitions.first.text).
1063
- to eq('a large common parrot, <bn>Cacatua galerita</bn>, predominantly' \
1064
- ' white, with yellow on the undersides of wings and tail and a' \
1065
- ' forward curving yellow crest, found in Australia, New Guinea' \
1066
- ' and nearby islands.')
1067
- end
1068
-
1069
- it "saves object's xml content" do
1070
- aggregate_failures do
1071
- expect(records.first.variants.first.xml_content).to eq 'white <tag>cockatoo</tag>'
1072
- expect(records.first.variants.last.to_html).to eq '<em>white</em> cockatoo'
1073
- end
1074
- end
1075
- end
1076
-
1077
- it 'parses ambigous items' do
1078
- items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), xpath: '/ambigous/my-items')
1079
- expect(items.map(&:name)).to eq(%w(first second third).map { |s| "My #{s} item" })
1080
- end
1081
-
1082
- context Article do
1083
- let(:article) { Article.parse(fixture_file('subclass_namespace.xml')) }
1084
-
1085
- it 'parses the publish options for Article and Photo' do
1086
- aggregate_failures do
1087
- expect(article.title).not_to be_nil
1088
- expect(article.text).not_to be_nil
1089
- expect(article.photos).not_to be_nil
1090
- expect(article.photos.first.title).not_to be_nil
1091
- end
1092
- end
1093
-
1094
- it 'parses the publish options for Article' do
1095
- expect(article.publish_options).not_to be_nil
1096
- end
1097
-
1098
- it 'parses the publish options for Photo' do
1099
- expect(article.photos.first.publish_options).not_to be_nil
1100
- end
1101
-
1102
- it 'onlies find only items at the parent level' do
1103
- expect(article.photos.length).to eq(1)
1104
- end
1105
- end
1106
-
1107
- describe 'Namespace is missing because an optional element that uses it is not present' do
1108
- it 'parses successfully' do
1109
- article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
1110
-
1111
- aggregate_failures do
1112
- expect(article).not_to be_nil
1113
- expect(article.title).not_to be_nil
1114
- expect(article.text).not_to be_nil
1115
- expect(article.photos).not_to be_nil
1116
- expect(article.photos.first.title).not_to be_nil
1117
- end
1118
- end
1119
- end
1120
-
1121
- describe 'with limit option' do
1122
- it 'returns results with limited size: 6' do
1123
- sizes = []
1124
- Post.parse(fixture_file('posts.xml'), in_groups_of: 6) do |a|
1125
- sizes << a.size
1126
- end
1127
- expect(sizes).to eq([6, 6, 6, 2])
1128
- end
1129
-
1130
- it 'returns results with limited size: 10' do
1131
- sizes = []
1132
- Post.parse(fixture_file('posts.xml'), in_groups_of: 10) do |a|
1133
- sizes << a.size
1134
- end
1135
- expect(sizes).to eq([10, 10])
1136
- end
1137
- end
1138
-
1139
- context 'when letting user set Nokogiri::XML::ParseOptions' do
1140
- let(:default) do
1141
- Class.new do
1142
- include HappyMapper
1143
- element :item, String
1144
- end
1145
- end
1146
- let(:custom) do
1147
- Class.new do
1148
- include HappyMapper
1149
- element :item, String
1150
- with_nokogiri_config(&:default_xml)
1151
- end
1152
- end
1153
-
1154
- it 'initializes @nokogiri_config_callback to nil' do
1155
- expect(default.nokogiri_config_callback).to be_nil
1156
- end
1157
-
1158
- it 'defaults to Nokogiri::XML::ParseOptions::STRICT' do
1159
- expect { default.parse(fixture_file('set_config_options.xml')) }.
1160
- to raise_error(Nokogiri::XML::SyntaxError)
1161
- end
1162
-
1163
- it 'accepts .on_config callback' do
1164
- expect(custom.nokogiri_config_callback).not_to be_nil
1165
- end
1166
-
1167
- it 'parses according to @nokogiri_config_callback' do
1168
- expect { custom.parse(fixture_file('set_config_options.xml')) }.not_to raise_error
1169
- end
1170
-
1171
- it 'can clear @nokogiri_config_callback' do
1172
- custom.with_nokogiri_config {}
1173
- expect { custom.parse(fixture_file('set_config_options.xml')) }.
1174
- to raise_error(Nokogiri::XML::SyntaxError)
1175
- end
1176
- end
1177
-
1178
- describe '#xml_value' do
1179
- it 'does not reformat the xml' do
1180
- xml = fixture_file('unformatted_address.xml')
1181
- address = Address.parse(xml, single: true)
1182
-
1183
- expect(address.xml_value).
1184
- to eq %(<address><street>Milchstrasse</street><housenumber>23</housenumber></address>)
1185
- end
1186
- end
1187
-
1188
- describe '#xml_content' do
1189
- it 'does not reformat the xml' do
1190
- xml = fixture_file('unformatted_address.xml')
1191
- address = Address.parse(xml)
1192
-
1193
- expect(address.xml_content).to eq %(<street>Milchstrasse</street><housenumber>23</housenumber>)
1194
- end
1195
- end
1196
-
1197
- describe '#to_xml' do
1198
- let(:original) { '<foo><bar>baz</bar></foo>' }
1199
- let(:parsed) { described_class.parse original }
1200
-
1201
- it 'has UTF-8 encoding by default' do
1202
- aggregate_failures do
1203
- expect(original.encoding).to eq Encoding::UTF_8
1204
- expect(parsed.to_xml.encoding).to eq Encoding::UTF_8
1205
- end
1206
- end
1207
- end
1208
- end