nokogiri-happymapper 0.5.7 → 0.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/CHANGELOG.md +10 -0
- data/README.md +244 -181
- data/lib/happymapper.rb +33 -13
- data/lib/happymapper/element.rb +3 -1
- data/lib/happymapper/item.rb +2 -0
- data/lib/happymapper/version.rb +1 -1
- data/spec/attributes_spec.rb +36 -0
- data/spec/fixtures/current_weather_missing_elements.xml +18 -0
- data/spec/happymapper_parse_spec.rb +3 -3
- data/spec/happymapper_spec.rb +6 -1
- data/spec/has_many_empty_array_spec.rb +43 -0
- data/spec/inheritance_spec.rb +47 -1
- data/spec/mixed_namespaces_spec.rb +61 -0
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
NjY1MTkxOTI0NjM1NDI2YTdjOGUwNzFhNjkzMWNiMzg5OGQ4ZTcyZGQ3NzZm
|
10
|
-
YmJlNzg0MjNlYjk4MDE5N2E0M2IyNjM5MGE5MmE3M2I3MzE2MTM4MmEwZTNi
|
11
|
-
OTMxMzkxMTViMGI3Mzc5MmY2ZGJjOGY5YTYyNjY1OTk3YTIwZDU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZjBmZjEwMzQ4NWRmYWJmYzFiMDRkZDYwYzU5N2VjY2U5ZTEwODU1ZmRiYjVm
|
14
|
-
Njc5OTIyNjA3NmJhMDNmOWNhM2RjOTI5NDZhNmEzODQ5ZDc0MzMxYTM0MWE0
|
15
|
-
MTQzMjYzMDY0Njg4ZGE3NWFjNTU1YmY3NDAwY2ExNDhmMDdhMDc=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cdf3f127daf46afa0d3d5e20bed4bf5551c29f46
|
4
|
+
data.tar.gz: 391a93426ddbd64054b5e5237796691c02d6ad1b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f0eaadc20671544e2cdb7738cb05359101de87dbeea066492abe2a65aa8016458d15cec88cce6bbba034b167605c5a3e5abd34d7e033df7f0d4101327c736ec
|
7
|
+
data.tar.gz: b690eb50747ebdffb6224e5715124de18c25cba9387c58db51b71d612ac0303be2ed38c4379afd78805a7d5043c9d4c0cf12a60e29edf7b01c66a636ce3d51f0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.5.8 / 2013-10-12
|
2
|
+
|
3
|
+
* Allow child elements to remove their parent's namespacing (dcarneiro)
|
4
|
+
* has_many elements were returning nil because the tag name was being ignored (haarts)
|
5
|
+
* Subclassed happymapper classes are allowed to override elements (benoist)
|
6
|
+
* Attributes on elements with dashes will properly created methods (alex-klepa)
|
7
|
+
* 'Embedded' attributes break parsing when parent element is not present (geoffwa)
|
8
|
+
|
9
|
+
## 0.5.7 / 2012-10-29
|
10
|
+
|
1
11
|
## 0.5.6 / 2012-10-29
|
2
12
|
|
3
13
|
* Add possibility to give a configuration block to Nokogiri when parsing (DieboldInc).
|
data/README.md
CHANGED
@@ -11,13 +11,13 @@ This project is a fork of the great work done first by
|
|
11
11
|
* [Nokogiri](http://nokogiri.org/) support
|
12
12
|
* Text nodes parsing
|
13
13
|
* Raw XML content parsing
|
14
|
-
*
|
15
|
-
*
|
16
|
-
* Fixes for instances of XML where a
|
14
|
+
* `#to_xml` support utilizing the same HappyMapper tags
|
15
|
+
* Numerous fixes for namespaces when using composition of classes
|
16
|
+
* Fixes for instances of XML where a namespace is defined but no elements with that namespace are found
|
17
17
|
|
18
18
|
## Installation
|
19
19
|
|
20
|
-
### [Rubygems](https://
|
20
|
+
### [Rubygems](https://rubyygems.org/gems/nokogiri-happymapper)
|
21
21
|
|
22
22
|
$ gem install nokogiri-happymapper
|
23
23
|
|
@@ -68,18 +68,20 @@ It is important to be aware that this no configuration parsing is limited in cap
|
|
68
68
|
|
69
69
|
Happymapper will let you easily model this information as a class:
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
71
|
+
```ruby
|
72
|
+
require 'happymapper'
|
73
|
+
|
74
|
+
class Address
|
75
|
+
include HappyMapper
|
76
|
+
|
77
|
+
tag 'address'
|
78
|
+
element :street, String, :tag => 'street'
|
79
|
+
element :postcode, String, :tag => 'postcode'
|
80
|
+
element :housenumber, Integer, :tag => 'housenumber'
|
81
|
+
element :city, String, :tag => 'city'
|
82
|
+
element :country, String, :tag => 'country'
|
83
|
+
end
|
84
|
+
```
|
83
85
|
|
84
86
|
To make a class HappyMapper compatible you simply `include HappyMapper` within the class definition. This takes care of all the work of defining all the speciality methods and magic you need to get running. As you can see we immediately start using these methods.
|
85
87
|
|
@@ -89,16 +91,20 @@ To make a class HappyMapper compatible you simply `include HappyMapper` within t
|
|
89
91
|
|
90
92
|
When you define an element with an accessor with the same name as the tag, this is the case for all the examples above, you can omit the `:tag`. These two element declaration are equivalent to each other:
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
+
```ruby
|
95
|
+
element :street, String, :tag => 'street'
|
96
|
+
element :street, String
|
97
|
+
```
|
94
98
|
|
95
99
|
Including the additional tag element is not going to hurt anything and in some cases will make it absolutely clear how these elements map to the XML. However, once you know this rule, it is hard not to want to save yourself the keystrokes.
|
96
100
|
|
97
101
|
Instead of `element` you may also use `has_one`:
|
98
102
|
|
99
|
-
|
100
|
-
|
101
|
-
|
103
|
+
```ruby
|
104
|
+
element :street, String, :tag => 'street'
|
105
|
+
element :street, String
|
106
|
+
has_one :street, String
|
107
|
+
```
|
102
108
|
|
103
109
|
These three statements are equivalent to each other.
|
104
110
|
|
@@ -106,8 +112,10 @@ These three statements are equivalent to each other.
|
|
106
112
|
|
107
113
|
With the mapping of the address XML articulated in our Address class it is time to parse the data:
|
108
114
|
|
109
|
-
|
110
|
-
|
115
|
+
```ruby
|
116
|
+
address = Address.parse(ADDRESS_XML_DATA, :single => true)
|
117
|
+
puts address.street
|
118
|
+
```
|
111
119
|
|
112
120
|
Assuming that the constant `ADDRESS_XML_DATA` contains a string representation of the address XML data this is fairly straight-forward save for the `parse` method.
|
113
121
|
|
@@ -115,8 +123,10 @@ The `parse` method, like `tag` and `element` are all added when you included Hap
|
|
115
123
|
|
116
124
|
But what about the `:single => true`? Right, that is because by default when your object is all done parsing it will be an array. In this case an array with one element, but an array none the less. So the following are equivalent to each other:
|
117
125
|
|
118
|
-
|
119
|
-
|
126
|
+
```ruby
|
127
|
+
address = Address.parse(ADDRESS_XML_DATA).first
|
128
|
+
address = Address.parse(ADDRESS_XML_DATA, :single => true)
|
129
|
+
```
|
120
130
|
|
121
131
|
The first one returns an array and we return the first instance, the second will do that work for us inside of parse.
|
122
132
|
|
@@ -135,33 +145,39 @@ What if our address XML was a little different, perhaps we allowed multiple stre
|
|
135
145
|
|
136
146
|
Similar to `element` or `has_one`, the declaration for when you have multiple elements you simply use:
|
137
147
|
|
138
|
-
|
148
|
+
```ruby
|
149
|
+
has_many :streets, String, :tag => 'street'
|
150
|
+
```
|
139
151
|
|
140
152
|
Your resulting `streets` method will now return an array.
|
141
153
|
|
142
|
-
|
143
|
-
|
154
|
+
```ruby
|
155
|
+
address = Address.parse(ADDRESS_XML_DATA, :single => true)
|
156
|
+
puts address.streets.join('\n')
|
157
|
+
```
|
144
158
|
|
145
159
|
Imagine that you have to write `streets.join('\n')` for the rest of eternity throughout your code. It would be a nightmare and one that you could avoid by creating your own convenience method.
|
146
160
|
|
147
|
-
|
161
|
+
```ruby
|
162
|
+
require 'happymapper'
|
148
163
|
|
149
|
-
|
150
|
-
|
164
|
+
class Address
|
165
|
+
include HappyMapper
|
151
166
|
|
152
|
-
|
167
|
+
tag 'address'
|
153
168
|
|
154
|
-
|
169
|
+
has_many :streets, String
|
155
170
|
|
156
|
-
|
157
|
-
|
158
|
-
|
171
|
+
def streets
|
172
|
+
@streets.join('\n')
|
173
|
+
end
|
159
174
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
175
|
+
element :postcode, String, :tag => 'postcode'
|
176
|
+
element :housenumber, String, :tag => 'housenumber'
|
177
|
+
element :city, String, :tag => 'city'
|
178
|
+
element :country, String, :tag => 'country'
|
179
|
+
end
|
180
|
+
```
|
165
181
|
|
166
182
|
Now when we call the method `streets` we get a single value, but we still have the instance variable `@streets` if we ever need to the values as an array.
|
167
183
|
|
@@ -179,7 +195,9 @@ Now when we call the method `streets` we get a single value, but we still have t
|
|
179
195
|
|
180
196
|
Attributes are absolutely the same as `element` or `has_many`
|
181
197
|
|
182
|
-
|
198
|
+
```ruby
|
199
|
+
attribute :location, String, :tag => 'location
|
200
|
+
```
|
183
201
|
|
184
202
|
Again, you can omit the tag if the attribute accessor symbol matches the name of the attribute.
|
185
203
|
|
@@ -196,22 +214,26 @@ Again, you can omit the tag if the attribute accessor symbol matches the name of
|
|
196
214
|
|
197
215
|
In this case you would need to map an element to a new `Link` class just to access `<link>`s attributes, except that there is an alternate syntax. Instead of
|
198
216
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
217
|
+
```ruby
|
218
|
+
class Feed
|
219
|
+
# ....
|
220
|
+
has_many :links, Link, :tag => 'link', :xpath => '.'
|
221
|
+
end
|
222
|
+
|
223
|
+
class Link
|
224
|
+
include HappyMapper
|
225
|
+
|
226
|
+
attribute :rel, String
|
227
|
+
attribute :type, String
|
228
|
+
attribute :href, String
|
229
|
+
end
|
230
|
+
```
|
211
231
|
|
212
232
|
You can drop the `Link` class and simply replace the `has_many` on `Feed` with
|
213
233
|
|
214
|
-
|
234
|
+
```ruby
|
235
|
+
element :link, String, :single => false, :attributes => { :rel => String, :type => String, :href => String }
|
236
|
+
```
|
215
237
|
|
216
238
|
As there is no content, the type given for `:link` (`String` above) is irrelevant, but `nil` won't work and other types may try to perform typecasting and fail. You can omit the :single => false for elements that only occur once within their parent.
|
217
239
|
|
@@ -233,14 +255,16 @@ Our address has a country and that country element has a code. Up until this poi
|
|
233
255
|
|
234
256
|
Well if we only going to parse country, on it's own, we would likely create a class mapping for it.
|
235
257
|
|
236
|
-
|
237
|
-
|
258
|
+
```ruby
|
259
|
+
class Country
|
260
|
+
include HappyMapper
|
238
261
|
|
239
|
-
|
262
|
+
tag 'country'
|
240
263
|
|
241
|
-
|
242
|
-
|
243
|
-
|
264
|
+
attribute :code, String
|
265
|
+
content :name, String
|
266
|
+
end
|
267
|
+
```
|
244
268
|
|
245
269
|
We are utilizing an `attribute` declaration and a new declaration called `content`.
|
246
270
|
|
@@ -248,27 +272,31 @@ We are utilizing an `attribute` declaration and a new declaration called `conten
|
|
248
272
|
|
249
273
|
Awesome, now if we were to redeclare our `Address` class we would use our new `Country` class.
|
250
274
|
|
251
|
-
|
252
|
-
|
275
|
+
```ruby
|
276
|
+
class Address
|
277
|
+
include HappyMapper
|
253
278
|
|
254
|
-
|
279
|
+
tag 'address'
|
255
280
|
|
256
|
-
|
281
|
+
has_many :streets, String, :tag => 'street'
|
257
282
|
|
258
|
-
|
259
|
-
|
260
|
-
|
283
|
+
def streets
|
284
|
+
@streets.join('\n')
|
285
|
+
end
|
261
286
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
287
|
+
element :postcode, String, :tag => 'postcode'
|
288
|
+
element :housenumber, String, :tag => 'housenumber'
|
289
|
+
element :city, String, :tag => 'city'
|
290
|
+
element :country, Country, :tag => 'country'
|
291
|
+
end
|
292
|
+
```
|
267
293
|
|
268
294
|
Instead of `String`, `Boolean`, or `Integer` we say that it is a `Country` and HappyMapper takes care of the details of continuing the XML mapping through the country element.
|
269
295
|
|
270
|
-
|
271
|
-
|
296
|
+
```ruby
|
297
|
+
address = Address.parse(ADDRESS_XML_DATA, :single => true)
|
298
|
+
puts address.country.code
|
299
|
+
```
|
272
300
|
|
273
301
|
A quick note, in the above example we used the constant `Country`. We could have used `'Country'`. The nice part of using the latter declaration, enclosed in quotes, is that you do not have to define your class before this class. So Country and Address can live in separate files and as long as both constants are available when it comes time to parse you are golden.
|
274
302
|
|
@@ -294,13 +322,14 @@ Getting to elements deep down within your XML can be a little more work if you d
|
|
294
322
|
|
295
323
|
You may want to map the sub-elements contained buried in the 'gallery' as top level items in the media. Traditionally you could use class composition to accomplish this task, however, using the xpath attribute you have the ability to shortcut some of that work.
|
296
324
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
has_one :title, String, :xpath => 'gallery/title'
|
301
|
-
has_one :link, String, :xpath => 'gallery/title/@href'
|
302
|
-
end
|
325
|
+
```ruby
|
326
|
+
class Media
|
327
|
+
include HappyMapper
|
303
328
|
|
329
|
+
has_one :title, String, :xpath => 'gallery/title'
|
330
|
+
has_one :link, String, :xpath => 'gallery/title/@href'
|
331
|
+
end
|
332
|
+
```
|
304
333
|
|
305
334
|
## Shared Functionality
|
306
335
|
|
@@ -308,85 +337,90 @@ You may want to map the sub-elements contained buried in the 'gallery' as top le
|
|
308
337
|
|
309
338
|
While mapping XML to objects you may arrive at a point where you have two or more very similar structures.
|
310
339
|
|
311
|
-
|
312
|
-
|
340
|
+
```ruby
|
341
|
+
class Article
|
342
|
+
include HappyMapper
|
313
343
|
|
314
|
-
|
315
|
-
|
316
|
-
|
344
|
+
has_one :title, String
|
345
|
+
has_one :author, String
|
346
|
+
has_one :published, Time
|
317
347
|
|
318
|
-
|
348
|
+
has_one :entry, String
|
319
349
|
|
320
|
-
|
350
|
+
end
|
321
351
|
|
322
|
-
|
323
|
-
|
352
|
+
class Gallery
|
353
|
+
include HappyMapper
|
324
354
|
|
325
|
-
|
326
|
-
|
327
|
-
|
355
|
+
has_one :title, String
|
356
|
+
has_one :author, String
|
357
|
+
has_one :published, Time
|
328
358
|
|
329
|
-
|
359
|
+
has_many :photos, String
|
330
360
|
|
331
|
-
|
361
|
+
end
|
362
|
+
```
|
332
363
|
|
333
364
|
In this example there are definitely two similarities between our two pieces of content. So much so that you might be included to create an inheritance structure to save yourself some keystrokes.
|
334
365
|
|
335
|
-
|
336
|
-
|
366
|
+
```ruby
|
367
|
+
class Content
|
368
|
+
include HappyMapper
|
337
369
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
370
|
+
has_one :title, String
|
371
|
+
has_one :author, String
|
372
|
+
has_one :published, Time
|
373
|
+
end
|
342
374
|
|
343
|
-
|
344
|
-
|
375
|
+
class Article < Content
|
376
|
+
include HappyMapper
|
345
377
|
|
346
|
-
|
347
|
-
|
378
|
+
has_one :entry, String
|
379
|
+
end
|
348
380
|
|
349
|
-
|
350
|
-
|
381
|
+
class Gallery < Content
|
382
|
+
include HappyMapper
|
351
383
|
|
352
|
-
|
353
|
-
|
384
|
+
has_many :photos, String
|
385
|
+
end
|
386
|
+
```
|
354
387
|
|
355
|
-
### Module Mixins
|
388
|
+
### Module Mixins Approach
|
356
389
|
|
357
390
|
You can also solve the above problem through mixins.
|
358
391
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
392
|
+
```ruby
|
393
|
+
module Content
|
394
|
+
def self.included(content)
|
395
|
+
content.has_one :title, String
|
396
|
+
content.has_one :author, String
|
397
|
+
content.has_one :published, Time
|
398
|
+
end
|
399
|
+
|
400
|
+
def published_time
|
401
|
+
@published.strftime("%H:%M:%S")
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
class Article
|
406
|
+
include HappyMapper
|
407
|
+
|
408
|
+
include Content
|
409
|
+
has_one :entry, String
|
410
|
+
end
|
411
|
+
|
412
|
+
class Gallery
|
413
|
+
include HappyMapper
|
414
|
+
|
415
|
+
include Content
|
416
|
+
has_many :photos, String
|
417
|
+
end
|
418
|
+
```
|
385
419
|
|
386
420
|
Here, when we include `Content` in both of these classes the module method `#included` is called and our class is given as a parameter. So we take that opportunity to do some surgery and define our happymapper elements as well as any other methods that may rely on those instance variables that come along in the package.
|
387
421
|
|
388
422
|
|
389
|
-
## Filtering with XPATH
|
423
|
+
## Filtering with XPATH (non-greedy)
|
390
424
|
|
391
425
|
I ran into a case where I wanted to capture all the pictures that were directly under media, but not the ones contained within a gallery.
|
392
426
|
|
@@ -405,25 +439,38 @@ I ran into a case where I wanted to capture all the pictures that were directly
|
|
405
439
|
|
406
440
|
The following `Media` class is where I started:
|
407
441
|
|
408
|
-
|
442
|
+
```ruby
|
443
|
+
require 'happymapper'
|
409
444
|
|
410
|
-
|
411
|
-
|
445
|
+
class Media
|
446
|
+
include HappyMapper
|
412
447
|
|
413
|
-
|
414
|
-
|
415
|
-
|
448
|
+
has_many :galleries, Gallery, :tag => 'gallery'
|
449
|
+
has_many :pictures, Picture, :tag => 'picture'
|
450
|
+
end
|
451
|
+
```
|
416
452
|
|
417
453
|
However when I parsed the media xml the number of pictures returned to me was 2, not 1.
|
418
454
|
|
419
|
-
|
420
|
-
|
455
|
+
```ruby
|
456
|
+
pictures = Media.parse(MEDIA_XML,:single => true).pictures
|
457
|
+
pictures.length.should == 1 # => Failed Expectation
|
458
|
+
```
|
459
|
+
|
460
|
+
The reason that 2 elements are returned and not 1 is because the default
|
461
|
+
mappings are assigned XPATH './/' which makes them greedy. Essentially by
|
462
|
+
default it will find all elements with the tag 'pictures' at the current
|
463
|
+
level of the document and anywhere else within the document.
|
421
464
|
|
422
|
-
|
465
|
+
To limit an element from being greedy and only finding elements at the
|
466
|
+
level of the current node you can specify an XPATH.
|
423
467
|
|
424
|
-
|
468
|
+
```ruby
|
469
|
+
has_many :pictures, Picture, :tag => 'picture', :xpath => '.'
|
470
|
+
```
|
425
471
|
|
426
|
-
|
472
|
+
`.` states that we are only interested in pictures that can be found directly
|
473
|
+
under the current node. So when we parse again we will have only our one element.
|
427
474
|
|
428
475
|
|
429
476
|
## Namespaces
|
@@ -443,28 +490,32 @@ Perhaps our `address` XML is really swarming with namespaces:
|
|
443
490
|
|
444
491
|
Here again is our address example with a made up namespace called `prefix` that comes direct to use from unicornland, a very magical place indeed. Well we are going to have to do some work on our class definition and that simply adding this one liner to the `Address` class:
|
445
492
|
|
446
|
-
|
447
|
-
|
493
|
+
```ruby
|
494
|
+
class Address
|
495
|
+
include HappyMapper
|
448
496
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
497
|
+
tag 'address'
|
498
|
+
namespace 'prefix'
|
499
|
+
# ... rest of the code ...
|
500
|
+
end
|
501
|
+
```
|
453
502
|
|
454
503
|
Of course, if that is too easy for you, you can append a `:namespace => 'prefix` to every one of the elements that you defined.
|
455
504
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
505
|
+
```ruby
|
506
|
+
has_many :street, String, :tag => 'street', :namespace => 'prefix'
|
507
|
+
element :postcode, String, :tag => 'postcode', :namespace => 'prefix'
|
508
|
+
element :housenumber, String, :tag => 'housenumber', :namespace => 'prefix'
|
509
|
+
element :city, String, :tag => 'city', :namespace => 'prefix'
|
510
|
+
element :country, Country, :tag => 'country', :namespace => 'prefix'
|
511
|
+
```
|
461
512
|
|
462
513
|
I definitely recommend the former, as it saves you a whole hell of lot of typing. However, there are times when appending a namespace to an element declaration is important and that is when it has a different namespace then `namespsace 'prefix'`.
|
463
514
|
|
464
515
|
Imagine that our `country` actually belonged to a completely different namespace.
|
465
516
|
|
466
517
|
<prefix:address location='home' xmlns:prefix="http://www.unicornland.com/prefix"
|
467
|
-
xmlns:
|
518
|
+
xmlns:different="http://www.trollcountry.com/different">
|
468
519
|
<prefix:street>Milchstrasse</prefix:street>
|
469
520
|
<prefix:street>Another Street</prefix:street>
|
470
521
|
<prefix:housenumber>23</prefix:housenumber>
|
@@ -475,7 +526,9 @@ Imagine that our `country` actually belonged to a completely different namespace
|
|
475
526
|
|
476
527
|
Well we would need to specify that namespace:
|
477
528
|
|
478
|
-
|
529
|
+
```ruby
|
530
|
+
element :country, Country, :tag => 'country', :namespace => 'different'
|
531
|
+
```
|
479
532
|
|
480
533
|
With that we should be able to parse as we once did.
|
481
534
|
|
@@ -483,9 +536,11 @@ With that we should be able to parse as we once did.
|
|
483
536
|
|
484
537
|
When dealing with large sets of XML that simply cannot or should not be placed into memory the objects can be handled in groups through the `:in_groups_of` parameter.
|
485
538
|
|
486
|
-
|
487
|
-
|
488
|
-
|
539
|
+
```ruby
|
540
|
+
Address.parse(LARGE_ADDRESS_XML_DATA,:in_groups_of => 5) do |group|
|
541
|
+
puts address.streets
|
542
|
+
end
|
543
|
+
```
|
489
544
|
|
490
545
|
This trivial block will parse the large set of XML data and in groups of 5 addresses at a time display the streets.
|
491
546
|
|
@@ -498,7 +553,9 @@ Saving a class to XML is as easy as calling `#to_xml`. The end result will be t
|
|
498
553
|
|
499
554
|
When you are saving data to xml it is often important to change or manipulate data to a particular format. For example, a time object:
|
500
555
|
|
501
|
-
|
556
|
+
```ruby
|
557
|
+
has_one :published_time, Time, :on_save => lambda {|time| time.strftime("%H:%M:%S") if time }
|
558
|
+
```
|
502
559
|
|
503
560
|
Here we add the options `:on_save` and specify a lambda which will be executed on the method call to `:published_time`.
|
504
561
|
|
@@ -506,7 +563,9 @@ Here we add the options `:on_save` and specify a lambda which will be executed o
|
|
506
563
|
|
507
564
|
When an element contains a nil value, or perhaps the result of the :on_save lambda correctly results in a nil value you will be happy that the element will not appear in the resulting XML. However, there are time when you will want to see that element and that's when `:state_when_nil` is there for you.
|
508
565
|
|
509
|
-
|
566
|
+
```ruby
|
567
|
+
has_one :favorite_color, String, :state_when_nil => true
|
568
|
+
```
|
510
569
|
|
511
570
|
The resulting XML will include the 'favorite_color' element even if the favorite color has not been specified.
|
512
571
|
|
@@ -515,28 +574,32 @@ The resulting XML will include the 'favorite_color' element even if the favorite
|
|
515
574
|
When an element, attribute, or text node is a value that you have no interest in
|
516
575
|
saving to XML, you can ensure that takes place by stating that it is `read only`.
|
517
576
|
|
518
|
-
|
519
|
-
|
577
|
+
```ruby
|
578
|
+
has_one :modified, Boolean, :read_only => true
|
579
|
+
attribute :temporary, Boolean, :read_only => true
|
580
|
+
```
|
520
581
|
|
521
582
|
This is useful if perhaps the incoming XML is different than the out-going XML.
|
522
583
|
|
523
584
|
### namespaces
|
524
585
|
|
525
|
-
|
586
|
+
Parsing the XML to objects only required you to simply specify the prefix of the namespace you wanted to parse, when you persist to xml you will need to define your namespaces so that they are correctly captured.
|
526
587
|
|
527
|
-
|
528
|
-
|
588
|
+
```ruby
|
589
|
+
class Address
|
590
|
+
include HappyMapper
|
529
591
|
|
530
|
-
|
531
|
-
|
592
|
+
register_namespace 'prefix', 'http://www.unicornland.com/prefix'
|
593
|
+
register_namespace 'different', 'http://www.trollcountry.com/different'
|
532
594
|
|
533
|
-
|
534
|
-
|
595
|
+
tag 'address'
|
596
|
+
namespace 'prefix'
|
535
597
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
598
|
+
has_many :street, String
|
599
|
+
element :postcode, String
|
600
|
+
element :housenumber, String
|
601
|
+
element :city, String
|
602
|
+
element :country, Country, :tag => 'country', :namespace => 'different'
|
541
603
|
|
542
|
-
|
604
|
+
end
|
605
|
+
```
|
data/lib/happymapper.rb
CHANGED
@@ -14,15 +14,17 @@ module HappyMapper
|
|
14
14
|
def self.included(base)
|
15
15
|
if !(base.superclass <= HappyMapper)
|
16
16
|
base.instance_eval do
|
17
|
-
@attributes =
|
18
|
-
@elements =
|
17
|
+
@attributes = {}
|
18
|
+
@elements = {}
|
19
19
|
@registered_namespaces = {}
|
20
20
|
@wrapper_anonymous_classes = {}
|
21
21
|
end
|
22
22
|
else
|
23
23
|
base.instance_eval do
|
24
|
-
@attributes =
|
25
|
-
|
24
|
+
@attributes =
|
25
|
+
superclass.instance_variable_get(:@attributes).dup
|
26
|
+
@elements =
|
27
|
+
superclass.instance_variable_get(:@elements).dup
|
26
28
|
@registered_namespaces =
|
27
29
|
superclass.instance_variable_get(:@registered_namespaces).dup
|
28
30
|
@wrapper_anonymous_classes =
|
@@ -52,7 +54,7 @@ module HappyMapper
|
|
52
54
|
#
|
53
55
|
def attribute(name, type, options={})
|
54
56
|
attribute = Attribute.new(name, type, options)
|
55
|
-
@attributes
|
57
|
+
@attributes[name] = attribute
|
56
58
|
attr_accessor attribute.method_name.intern
|
57
59
|
end
|
58
60
|
|
@@ -63,7 +65,7 @@ module HappyMapper
|
|
63
65
|
# an empty array is returned when there have been no attributes defined.
|
64
66
|
#
|
65
67
|
def attributes
|
66
|
-
@attributes
|
68
|
+
@attributes.values
|
67
69
|
end
|
68
70
|
|
69
71
|
#
|
@@ -107,7 +109,7 @@ module HappyMapper
|
|
107
109
|
#
|
108
110
|
def element(name, type, options={})
|
109
111
|
element = Element.new(name, type, options)
|
110
|
-
@elements
|
112
|
+
@elements[name] = element
|
111
113
|
attr_accessor element.method_name.intern
|
112
114
|
end
|
113
115
|
|
@@ -119,7 +121,7 @@ module HappyMapper
|
|
119
121
|
# defined.
|
120
122
|
#
|
121
123
|
def elements
|
122
|
-
@elements
|
124
|
+
@elements.values
|
123
125
|
end
|
124
126
|
|
125
127
|
#
|
@@ -338,18 +340,36 @@ module HappyMapper
|
|
338
340
|
nodes = []
|
339
341
|
|
340
342
|
# when finding nodes, do it in this order:
|
341
|
-
# 1. specified tag
|
343
|
+
# 1. specified tag if one has been provided
|
342
344
|
# 2. name of element
|
343
345
|
# 3. tag_name (derived from class name by default)
|
344
346
|
|
347
|
+
# If a tag has been provided we need to search for it.
|
345
348
|
|
346
|
-
|
349
|
+
if options.key?(:tag)
|
347
350
|
begin
|
348
|
-
nodes = node.xpath(xpath +
|
351
|
+
nodes = node.xpath(xpath + options[:tag].to_s, namespaces)
|
349
352
|
rescue
|
350
|
-
|
353
|
+
# This exception takes place when the namespace is often not found
|
354
|
+
# and we should continue on with the empty array of nodes.
|
351
355
|
end
|
352
|
-
|
356
|
+
else
|
357
|
+
|
358
|
+
# This is the default case when no tag value is provided.
|
359
|
+
# First we use the name of the element `items` in `has_many items`
|
360
|
+
# Second we use the tag name which is the name of the class cleaned up
|
361
|
+
|
362
|
+
[options[:name], tag_name].compact.each do |xpath_ext|
|
363
|
+
begin
|
364
|
+
nodes = node.xpath(xpath + xpath_ext.to_s, namespaces)
|
365
|
+
rescue
|
366
|
+
break
|
367
|
+
# This exception takes place when the namespace is often not found
|
368
|
+
# and we should continue with the empty array of nodes or keep looking
|
369
|
+
end
|
370
|
+
break if nodes && !nodes.empty?
|
371
|
+
end
|
372
|
+
|
353
373
|
end
|
354
374
|
|
355
375
|
nodes
|
data/lib/happymapper/element.rb
CHANGED
@@ -35,12 +35,14 @@ module HappyMapper
|
|
35
35
|
if options[:attributes].is_a?(Hash)
|
36
36
|
result = result.first unless result.respond_to?(:attribute_nodes)
|
37
37
|
|
38
|
+
return unless result.respond_to?(:attribute_nodes)
|
39
|
+
|
38
40
|
result.attribute_nodes.each do |xml_attribute|
|
39
41
|
if attribute_options = options[:attributes][xml_attribute.name.to_sym]
|
40
42
|
attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace, xpath_options)
|
41
43
|
|
42
44
|
result.instance_eval <<-EOV
|
43
|
-
def value.#{xml_attribute.name}
|
45
|
+
def value.#{xml_attribute.name.gsub(/\-/, '_')}
|
44
46
|
#{attribute_value.inspect}
|
45
47
|
end
|
46
48
|
EOV
|
data/lib/happymapper/item.rb
CHANGED
@@ -32,6 +32,8 @@ module HappyMapper
|
|
32
32
|
#
|
33
33
|
def from_xml_node(node, namespace, xpath_options)
|
34
34
|
|
35
|
+
namespace = options[:namespace] if options.key?(:namespace)
|
36
|
+
|
35
37
|
if suported_type_registered?
|
36
38
|
find(node, namespace, xpath_options) { |n| process_node_as_supported_type(n) }
|
37
39
|
elsif constant == XmlContent
|
data/lib/happymapper/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Attribute Method Conversion" do
|
4
|
+
|
5
|
+
let(:xml_document) do
|
6
|
+
%{<document>
|
7
|
+
<link data-src='http://cooking.com/roastbeef' type='recipe'>Roast Beef</link>
|
8
|
+
</document>}
|
9
|
+
end
|
10
|
+
|
11
|
+
module AttributeMethodConversion
|
12
|
+
class Document
|
13
|
+
include HappyMapper
|
14
|
+
|
15
|
+
has_many :link, String, :attributes => { :'data-src' => String, :type => String, :href => String }
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:document) do
|
21
|
+
AttributeMethodConversion::Document.parse(xml_document,single: true)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "link" do
|
25
|
+
expect(document.link).to eq ["Roast Beef"]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "link.data_src" do
|
29
|
+
expect(document.link.first.data_src).to eq "http://cooking.com/roastbeef"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "link.type" do
|
33
|
+
expect(document.link.first.type).to eq "recipe"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<aws:weather xmlns:aws="http://www.aws.com/aws">
|
2
|
+
<aws:api version="2.0"/>
|
3
|
+
<aws:WebURL>http://weather.weatherbug.com/IN/Carmel-weather.html?ZCode=Z5546&Units=0&stat=MOCAR</aws:WebURL>
|
4
|
+
<aws:ob>
|
5
|
+
<aws:ob-date>
|
6
|
+
<aws:year number="2008"/>
|
7
|
+
<aws:month number="12" text="December" abbrv="Dec"/>
|
8
|
+
<aws:day number="30" text="Tuesday" abbrv="Tue"/>
|
9
|
+
<aws:hour number="4" hour-24="16"/>
|
10
|
+
<aws:minute number="18"/>
|
11
|
+
<aws:second number="01"/>
|
12
|
+
<aws:am-pm abbrv="PM"/>
|
13
|
+
<aws:time-zone offset="-5" text="Eastern Standard Time" abbrv="EST"/>
|
14
|
+
</aws:ob-date>
|
15
|
+
<aws:feels-like units="&deg;F">51</aws:feels-like>
|
16
|
+
<aws:temp units="&deg;F">51.8</aws:temp>
|
17
|
+
</aws:ob>
|
18
|
+
</aws:weather>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe HappyMapper do
|
4
4
|
|
@@ -45,7 +45,7 @@ describe HappyMapper do
|
|
45
45
|
|
46
46
|
subject { described_class.parse fixture_file('subclass_namespace.xml') }
|
47
47
|
|
48
|
-
it "should parse the elements
|
48
|
+
it "should parse the elements and values correctly" do
|
49
49
|
subject.title.should == "article title"
|
50
50
|
subject.photo.publish_options.author.should == "Stephanie"
|
51
51
|
subject.gallery.photo.title.should == "photo title"
|
@@ -70,7 +70,7 @@ describe HappyMapper do
|
|
70
70
|
subject.image.should == [ "image1", "image2" ]
|
71
71
|
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
end
|
75
75
|
|
76
76
|
context "xml with multiple namespaces" do
|
data/spec/happymapper_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module Analytics
|
4
5
|
class Property
|
@@ -780,6 +781,10 @@ describe HappyMapper do
|
|
780
781
|
feed.link.last.href.should == 'http://www.example.com/tv_shows.atom'
|
781
782
|
end
|
782
783
|
|
784
|
+
it "parses xml with optional elements with embedded attributes" do
|
785
|
+
expect { CurrentWeather.parse(fixture_file('current_weather_missing_elements.xml')) }.to_not raise_error()
|
786
|
+
end
|
787
|
+
|
783
788
|
it "returns nil rather than empty array for absent values when :single => true" do
|
784
789
|
address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true)
|
785
790
|
address.should be_nil
|
@@ -1099,7 +1104,7 @@ describe HappyMapper do
|
|
1099
1104
|
end
|
1100
1105
|
|
1101
1106
|
it 'parses according to @nokogiri_config_callback' do
|
1102
|
-
expect { custom.parse(fixture_file('set_config_options.xml')) }.to_not raise_error
|
1107
|
+
expect { custom.parse(fixture_file('set_config_options.xml')) }.to_not raise_error
|
1103
1108
|
end
|
1104
1109
|
|
1105
1110
|
it 'can clear @nokogiri_config_callback' do
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Sheep
|
4
|
+
class Item
|
5
|
+
include HappyMapper
|
6
|
+
end
|
7
|
+
|
8
|
+
class Navigator
|
9
|
+
include HappyMapper
|
10
|
+
tag 'navigator'
|
11
|
+
|
12
|
+
# This is purposefully set to have the name 'items' with the tag 'item'.
|
13
|
+
# The idea is that it should not find the empty items contained within the
|
14
|
+
# xml and return an empty array. This exercises the order of how nodes
|
15
|
+
# are searched for within an XML document.
|
16
|
+
has_many :items, Item, tag: 'item'
|
17
|
+
|
18
|
+
has_many :items_with_a_different_name, Item, tag: 'item'
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "emptyness" do
|
24
|
+
let(:xml) do
|
25
|
+
<<-EOF
|
26
|
+
<navigator>
|
27
|
+
<items/>
|
28
|
+
</navigator>
|
29
|
+
EOF
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:navigator) do
|
33
|
+
Sheep::Navigator.parse(xml)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns an empty array" do
|
37
|
+
navigator.items_with_a_different_name.should be_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns an empty array" do
|
41
|
+
navigator.items.should be_empty
|
42
|
+
end
|
43
|
+
end
|
data/spec/inheritance_spec.rb
CHANGED
@@ -19,6 +19,52 @@ describe "Using inheritance to share elements and attributes" do
|
|
19
19
|
has_many :immunities, String
|
20
20
|
end
|
21
21
|
|
22
|
+
class Overwrite < Parent
|
23
|
+
include HappyMapper
|
24
|
+
|
25
|
+
attribute :love, String
|
26
|
+
element :genetics, Integer
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "Overwrite" do
|
30
|
+
let(:subject) do
|
31
|
+
xml = '<overwrite love="love" naivety="trusting"><genetics>1001</genetics><immunities>Chicken Pox</immunities></overwrite>'
|
32
|
+
Overwrite.parse(xml, single: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'overrides the parent elements and attributes' do
|
36
|
+
expect(Overwrite.attributes.count).to be == Parent.attributes.count
|
37
|
+
expect(Overwrite.elements.count).to be == Parent.elements.count
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when parsing xml" do
|
41
|
+
it 'parses the new overwritten attribut' do
|
42
|
+
expect(subject.love).to be == "love"
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'parses the new overwritten element' do
|
46
|
+
expect(subject.genetics).to be == 1001
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when saving to xml" do
|
51
|
+
subject do
|
52
|
+
overwrite = Overwrite.new
|
53
|
+
overwrite.genetics = 1
|
54
|
+
overwrite.love = "love"
|
55
|
+
Nokogiri::XML(overwrite.to_xml).root
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'has only 1 genetics element' do
|
59
|
+
expect(subject.xpath('//genetics').count).to be == 1
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'has only 1 love attribute' do
|
63
|
+
expect(subject.xpath('@love').text).to be == "love"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
22
68
|
describe "Child", "a subclass of the Parent" do
|
23
69
|
let(:subject) do
|
24
70
|
xml = '<child love="99" naivety="trusting"><genetics>ABBA</genetics><immunities>Chicken Pox</immunities></child>'
|
@@ -58,4 +104,4 @@ describe "Using inheritance to share elements and attributes" do
|
|
58
104
|
end
|
59
105
|
|
60
106
|
end
|
61
|
-
end
|
107
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A document with mixed namespaces" do
|
4
|
+
|
5
|
+
#
|
6
|
+
# Note that the parent element of the xml has the namespacing. The elements
|
7
|
+
# contained within the xml do not share the parent element namespace so a
|
8
|
+
# user of the library would likely need to clear the namespace on each of
|
9
|
+
# these child elements.
|
10
|
+
#
|
11
|
+
let(:xml_document) do
|
12
|
+
%{<prefix:address location='home' xmlns:prefix="http://www.unicornland.com/prefix"
|
13
|
+
xmlns:different="http://www.trollcountry.com/different">
|
14
|
+
<street>Milchstrasse</street>
|
15
|
+
<street>Another Street</street>
|
16
|
+
<housenumber>23</housenumber>
|
17
|
+
<different:postcode>26131</different:postcode>
|
18
|
+
<city>Oldenburg</city>
|
19
|
+
</prefix:address>}
|
20
|
+
end
|
21
|
+
|
22
|
+
module MixedNamespaces
|
23
|
+
class Address
|
24
|
+
include HappyMapper
|
25
|
+
|
26
|
+
namespace :prefix
|
27
|
+
tag :address
|
28
|
+
|
29
|
+
# Here each of the elements have their namespace set to nil to reset their
|
30
|
+
# namespace so that it is not the same as the prefix namespace
|
31
|
+
|
32
|
+
has_many :streets, String, tag: 'street', namespace: nil
|
33
|
+
|
34
|
+
has_one :house_number, String, tag: 'housenumber', namespace: nil
|
35
|
+
has_one :postcode, String, namespace: 'different'
|
36
|
+
has_one :city, String, namespace: nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:address) do
|
41
|
+
MixedNamespaces::Address.parse(xml_document, single: true)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it "has the correct streets" do
|
46
|
+
expect(address.streets).to eq [ "Milchstrasse", "Another Street" ]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "house number" do
|
50
|
+
expect(address.house_number).to eq "23"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "postcode" do
|
54
|
+
expect(address.postcode).to eq "26131"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "city" do
|
58
|
+
expect(address.city).to eq "Oldenburg"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nokogiri-happymapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damien Le Berrigaud
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- README.md
|
64
64
|
- CHANGELOG.md
|
65
65
|
- spec/attribute_default_value_spec.rb
|
66
|
+
- spec/attributes_spec.rb
|
66
67
|
- spec/fixtures/address.xml
|
67
68
|
- spec/fixtures/ambigous_items.xml
|
68
69
|
- spec/fixtures/analytics.xml
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- spec/fixtures/atom.xml
|
71
72
|
- spec/fixtures/commit.xml
|
72
73
|
- spec/fixtures/current_weather.xml
|
74
|
+
- spec/fixtures/current_weather_missing_elements.xml
|
73
75
|
- spec/fixtures/default_namespace_combi.xml
|
74
76
|
- spec/fixtures/dictionary.xml
|
75
77
|
- spec/fixtures/family_tree.xml
|
@@ -95,8 +97,10 @@ files:
|
|
95
97
|
- spec/happymapper/text_node_spec.rb
|
96
98
|
- spec/happymapper_parse_spec.rb
|
97
99
|
- spec/happymapper_spec.rb
|
100
|
+
- spec/has_many_empty_array_spec.rb
|
98
101
|
- spec/ignay_spec.rb
|
99
102
|
- spec/inheritance_spec.rb
|
103
|
+
- spec/mixed_namespaces_spec.rb
|
100
104
|
- spec/parse_with_object_to_update_spec.rb
|
101
105
|
- spec/spec_helper.rb
|
102
106
|
- spec/to_xml_spec.rb
|
@@ -114,22 +118,23 @@ require_paths:
|
|
114
118
|
- lib
|
115
119
|
required_ruby_version: !ruby/object:Gem::Requirement
|
116
120
|
requirements:
|
117
|
-
- -
|
121
|
+
- - '>='
|
118
122
|
- !ruby/object:Gem::Version
|
119
123
|
version: '0'
|
120
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
125
|
requirements:
|
122
|
-
- -
|
126
|
+
- - '>='
|
123
127
|
- !ruby/object:Gem::Version
|
124
128
|
version: '0'
|
125
129
|
requirements: []
|
126
130
|
rubyforge_project:
|
127
|
-
rubygems_version: 2.0.
|
131
|
+
rubygems_version: 2.0.6
|
128
132
|
signing_key:
|
129
133
|
specification_version: 3
|
130
134
|
summary: Provides a simple way to map XML to Ruby Objects and back again.
|
131
135
|
test_files:
|
132
136
|
- spec/attribute_default_value_spec.rb
|
137
|
+
- spec/attributes_spec.rb
|
133
138
|
- spec/fixtures/address.xml
|
134
139
|
- spec/fixtures/ambigous_items.xml
|
135
140
|
- spec/fixtures/analytics.xml
|
@@ -137,6 +142,7 @@ test_files:
|
|
137
142
|
- spec/fixtures/atom.xml
|
138
143
|
- spec/fixtures/commit.xml
|
139
144
|
- spec/fixtures/current_weather.xml
|
145
|
+
- spec/fixtures/current_weather_missing_elements.xml
|
140
146
|
- spec/fixtures/default_namespace_combi.xml
|
141
147
|
- spec/fixtures/dictionary.xml
|
142
148
|
- spec/fixtures/family_tree.xml
|
@@ -162,8 +168,10 @@ test_files:
|
|
162
168
|
- spec/happymapper/text_node_spec.rb
|
163
169
|
- spec/happymapper_parse_spec.rb
|
164
170
|
- spec/happymapper_spec.rb
|
171
|
+
- spec/has_many_empty_array_spec.rb
|
165
172
|
- spec/ignay_spec.rb
|
166
173
|
- spec/inheritance_spec.rb
|
174
|
+
- spec/mixed_namespaces_spec.rb
|
167
175
|
- spec/parse_with_object_to_update_spec.rb
|
168
176
|
- spec/spec_helper.rb
|
169
177
|
- spec/to_xml_spec.rb
|
@@ -171,3 +179,4 @@ test_files:
|
|
171
179
|
- spec/wilcard_tag_name_spec.rb
|
172
180
|
- spec/wrap_spec.rb
|
173
181
|
- spec/xpath_spec.rb
|
182
|
+
has_rdoc:
|