nokogiri-happymapper 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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