nokogiri-happymapper 0.8.1 → 0.10.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +1 -4
- data/lib/happymapper/anonymous_mapper.rb +6 -5
- data/lib/happymapper/class_methods.rb +466 -0
- data/lib/happymapper/element.rb +3 -3
- data/lib/happymapper/item.rb +19 -13
- data/lib/happymapper/supported_types.rb +4 -6
- data/lib/happymapper/syntax_error.rb +6 -0
- data/lib/happymapper/version.rb +1 -1
- data/lib/happymapper.rb +54 -505
- data/lib/nokogiri-happymapper.rb +1 -1
- metadata +100 -107
- data/spec/features/after_parse_callbacks_spec.rb +0 -32
- data/spec/features/attribute_default_value_spec.rb +0 -48
- data/spec/features/attributes_spec.rb +0 -35
- data/spec/features/has_many_empty_array_spec.rb +0 -44
- data/spec/features/ignay_spec.rb +0 -92
- data/spec/features/inheritance_spec.rb +0 -121
- data/spec/features/mixed_namespaces_spec.rb +0 -60
- data/spec/features/parse_with_object_to_update_spec.rb +0 -116
- data/spec/features/same_tag_different_meaning_spec.rb +0 -44
- data/spec/features/to_xml_spec.rb +0 -205
- data/spec/features/to_xml_with_namespaces_spec.rb +0 -237
- data/spec/features/wildcard_tag_name_spec.rb +0 -110
- data/spec/features/wrap_spec.rb +0 -87
- data/spec/features/xpath_spec.rb +0 -84
- data/spec/fixtures/address.xml +0 -9
- data/spec/fixtures/ambigous_items.xml +0 -22
- data/spec/fixtures/analytics.xml +0 -61
- data/spec/fixtures/analytics_profile.xml +0 -127
- data/spec/fixtures/atom.xml +0 -19
- data/spec/fixtures/commit.xml +0 -52
- data/spec/fixtures/current_weather.xml +0 -89
- data/spec/fixtures/current_weather_missing_elements.xml +0 -18
- data/spec/fixtures/default_namespace_combi.xml +0 -6
- data/spec/fixtures/dictionary.xml +0 -20
- data/spec/fixtures/family_tree.xml +0 -21
- data/spec/fixtures/inagy.xml +0 -85
- data/spec/fixtures/lastfm.xml +0 -355
- data/spec/fixtures/multiple_namespaces.xml +0 -170
- data/spec/fixtures/multiple_primitives.xml +0 -5
- data/spec/fixtures/optional_attributes.xml +0 -6
- data/spec/fixtures/pita.xml +0 -133
- data/spec/fixtures/posts.xml +0 -23
- data/spec/fixtures/product_default_namespace.xml +0 -18
- data/spec/fixtures/product_no_namespace.xml +0 -10
- data/spec/fixtures/product_single_namespace.xml +0 -10
- data/spec/fixtures/quarters.xml +0 -19
- data/spec/fixtures/radar.xml +0 -21
- data/spec/fixtures/set_config_options.xml +0 -3
- data/spec/fixtures/statuses.xml +0 -422
- data/spec/fixtures/subclass_namespace.xml +0 -50
- data/spec/fixtures/unformatted_address.xml +0 -1
- data/spec/fixtures/wrapper.xml +0 -11
- data/spec/happymapper/anonymous_mapper_spec.rb +0 -158
- data/spec/happymapper/attribute_spec.rb +0 -12
- data/spec/happymapper/item_spec.rb +0 -177
- data/spec/happymapper_spec.rb +0 -1208
- data/spec/spec_helper.rb +0 -25
data/spec/happymapper_spec.rb
DELETED
@@ -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
|