multi_xml 0.2.2 → 0.3.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.

Potentially problematic release.


This version of multi_xml might be problematic. Click here for more details.

@@ -6,28 +6,16 @@ module MultiXml
6
6
  extend self
7
7
  def parse_error; ::REXML::ParseException; end
8
8
 
9
- CONTENT_ROOT = '__content__'.freeze unless defined?(CONTENT_ROOT)
10
-
11
- # Parse an XML Document string or IO into a simple hash using REXML
9
+ # Parse an XML Document IO into a simple hash using REXML
12
10
  #
13
11
  # xml::
14
- # XML Document string or IO to parse
12
+ # XML Document IO to parse
15
13
  def parse(xml)
16
- if !xml.respond_to?(:read)
17
- xml = StringIO.new(xml || '')
18
- end
19
-
20
- char = xml.getc
21
- if char.nil?
22
- {}
14
+ doc = REXML::Document.new(xml)
15
+ if doc.root
16
+ merge_element!({}, doc.root)
23
17
  else
24
- xml.ungetc(char)
25
- doc = REXML::Document.new(xml)
26
- if doc.root
27
- merge_element!({}, doc.root)
28
- else
29
- raise REXML::ParseException, "The document #{doc.to_s.inspect} does not have a valid root"
30
- end
18
+ raise REXML::ParseException, "The document #{doc.to_s.inspect} does not have a valid root"
31
19
  end
32
20
  end
33
21
 
@@ -72,7 +60,7 @@ module MultiXml
72
60
  # must use value to prevent double-escaping
73
61
  texts = ''
74
62
  element.texts.each { |t| texts << t.value }
75
- merge!(hash, CONTENT_ROOT, texts)
63
+ merge!(hash, MultiXml::CONTENT_ROOT, texts)
76
64
  end
77
65
  end
78
66
 
@@ -118,7 +106,7 @@ module MultiXml
118
106
  # element::
119
107
  # XML element to be checked.
120
108
  def empty_content?(element)
121
- element.texts.join.blank?
109
+ element.texts.join.strip.empty?
122
110
  end
123
111
  end
124
112
  end
@@ -1,3 +1,3 @@
1
1
  module MultiXml
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,26 +1,24 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require File.expand_path('../lib/multi_xml/version', __FILE__)
3
3
 
4
- Gem::Specification.new do |s|
5
- s.add_development_dependency('libxml-ruby', '~> 1.1')
6
- s.add_development_dependency('maruku', '~> 0.6')
7
- s.add_development_dependency('nokogiri', '~> 1.4')
8
- s.add_development_dependency('rake', '~> 0.8')
9
- s.add_development_dependency('rspec', '~> 2.5')
10
- s.add_development_dependency('simplecov', '~> 0.4')
11
- s.add_development_dependency('yard', '~> 0.6')
12
- s.add_development_dependency('ZenTest', '~> 4.5')
13
- s.name = 'multi_xml'
14
- s.version = MultiXml::VERSION
15
- s.platform = Gem::Platform::RUBY
16
- s.authors = ["Erik Michaels-Ober"]
17
- s.email = ['sferik@gmail.com']
18
- s.homepage = 'http://rubygems.org/gems/multi_xml'
19
- s.summary = %q{A generic swappable back-end for XML parsing}
20
- s.description = %q{A gem to provide swappable XML backends utilizing LibXML, Nokogiri, or REXML.}
21
- s.rubyforge_project = 'multi_xml'
22
- s.files = `git ls-files`.split("\n")
23
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
- s.require_paths = ['lib']
4
+ Gem::Specification.new do |gem|
5
+ gem.add_development_dependency 'ZenTest', '~> 4.5'
6
+ gem.add_development_dependency 'maruku', '~> 0.6'
7
+ gem.add_development_dependency 'nokogiri', '~> 1.4'
8
+ gem.add_development_dependency 'rake', '~> 0.9'
9
+ gem.add_development_dependency 'rspec', '~> 2.6'
10
+ gem.add_development_dependency 'simplecov', '~> 0.4'
11
+ gem.add_development_dependency 'yard', '~> 0.7'
12
+ gem.name = 'multi_xml'
13
+ gem.version = MultiXml::VERSION
14
+ gem.platform = Gem::Platform::RUBY
15
+ gem.author = "Erik Michaels-Ober"
16
+ gem.email = 'sferik@gmail.com'
17
+ gem.homepage = 'https://github.com/sferik/multi_xml'
18
+ gem.summary = %q{A generic swappable back-end for XML parsing}
19
+ gem.description = %q{A gem to provide swappable XML backends utilizing LibXML, Nokogiri, or REXML.}
20
+ gem.files = `git ls-files`.split("\n")
21
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ gem.require_paths = ['lib']
26
24
  end
@@ -1,4 +1,3 @@
1
1
  require 'simplecov'
2
2
  SimpleCov.start
3
3
  require 'multi_xml'
4
- require 'rspec'
@@ -1,4 +1,5 @@
1
1
  require 'helper'
2
+ require 'parser_shared_example'
2
3
 
3
4
  class MockDecoder; end
4
5
 
@@ -6,16 +7,16 @@ describe "MultiXml" do
6
7
  context "Parsers" do
7
8
  it "should default to the best available gem" do
8
9
  pending
9
- MultiXml.parser.name.should == 'MultiXml::Parsers::Rexml'
10
+ MultiXml.parser.name.should be == 'MultiXml::Parsers::Rexml'
10
11
  require 'nokogiri'
11
- MultiXml.parser.name.should == 'MultiXml::Parsers::Nokogiri'
12
+ MultiXml.parser.name.should be == 'MultiXml::Parsers::Nokogiri'
12
13
  require 'libxml'
13
14
  MultiXml.parser.name.should == 'MultiXml::Parsers::Libxml'
14
15
  end
15
16
 
16
17
  it "should be settable via a symbol" do
17
- MultiXml.parser = :libxml
18
- MultiXml.parser.name.should == 'MultiXml::Parsers::Libxml'
18
+ MultiXml.parser = :nokogiri
19
+ MultiXml.parser.name.should == 'MultiXml::Parsers::Nokogiri'
19
20
  end
20
21
 
21
22
  it "should be settable via a class" do
@@ -24,554 +25,16 @@ describe "MultiXml" do
24
25
  end
25
26
  end
26
27
 
27
- Dir.glob('lib/multi_xml/parsers/**/*.rb').map{|file| File.basename(file, ".rb").split('_').map{|s| s.capitalize}.join('')}.each do |parser|
28
- context "Parsers::#{parser}" do
29
- before do
30
- begin
31
- MultiXml.parser = parser
32
- rescue LoadError
33
- pending "Parser #{parser} couldn't be loaded"
34
- end
35
- end
36
-
37
- describe ".parse" do
38
- context "a blank string" do
39
- before do
40
- @xml = ''
41
- end
42
-
43
- it "should return an empty Hash" do
44
- MultiXml.parse(@xml).should == {}
45
- end
46
- end
47
-
48
- context "a whitespace string" do
49
- before do
50
- @xml = ' '
51
- end
52
-
53
- it "should return an empty Hash" do
54
- MultiXml.parse(@xml).should == {}
55
- end
56
- end
57
-
58
- context "an invalid XML document" do
59
- before do
60
- @xml = '<open></close>'
61
- end
62
-
63
- it "should raise MultiXml::ParseError" do
64
- lambda do
65
- MultiXml.parse(@xml)
66
- end.should raise_error(MultiXml::ParseError)
67
- end
68
- end
69
-
70
- context "a valid XML document" do
71
- before do
72
- @xml = '<user/>'
73
- end
74
-
75
- it "should parse correctly" do
76
- MultiXml.parse(@xml).should == {'user' => nil}
77
- end
78
-
79
- context "with CDATA" do
80
- before do
81
- @xml = '<user><![CDATA[Erik Michaels-Ober]]></user>'
82
- end
83
-
84
- it "should return the correct CDATA" do
85
- MultiXml.parse(@xml)['user'].should == "Erik Michaels-Ober"
86
- end
87
- end
88
-
89
- context "with content" do
90
- before do
91
- @xml = '<user>Erik Michaels-Ober</user>'
92
- end
93
-
94
- it "should return the correct content" do
95
- MultiXml.parse(@xml)['user'].should == "Erik Michaels-Ober"
96
- end
97
- end
98
-
99
- context "with an attribute" do
100
- before do
101
- @xml = '<user name="Erik Michaels-Ober"/>'
102
- end
103
-
104
- it "should return the correct attribute" do
105
- MultiXml.parse(@xml)['user']['name'].should == "Erik Michaels-Ober"
106
- end
107
- end
108
-
109
- context "with multiple attributes" do
110
- before do
111
- @xml = '<user name="Erik Michaels-Ober" screen_name="sferik"/>'
112
- end
113
-
114
- it "should return the correct attributes" do
115
- MultiXml.parse(@xml)['user']['name'].should == "Erik Michaels-Ober"
116
- MultiXml.parse(@xml)['user']['screen_name'].should == "sferik"
117
- end
118
- end
119
-
120
- context "with :symbolize_keys => true" do
121
- before do
122
- @xml = '<user><name>Erik Michaels-Ober</name></user>'
123
- end
124
-
125
- it "should symbolize keys" do
126
- MultiXml.parse(@xml, :symbolize_keys => true).should == {:user => {:name => "Erik Michaels-Ober"}}
127
- end
128
- end
129
-
130
- context "when value is true" do
131
- before do
132
- pending
133
- @xml = '<tag>true</tag>'
134
- end
135
-
136
- it "should return true" do
137
- MultiXml.parse(@xml)['tag'].should be_true
138
- end
139
- end
140
-
141
- context "when value is false" do
142
- before do
143
- pending
144
- @xml = '<tag>false</tag>'
145
- end
146
-
147
- it "should return false" do
148
- MultiXml.parse(@xml)['tag'].should be_false
149
- end
150
- end
151
-
152
- context "when key is id" do
153
- before do
154
- pending
155
- @xml = '<id>1</id>'
156
- end
157
-
158
- it "should return a Fixnum" do
159
- MultiXml.parse(@xml)['id'].should be_a(Fixnum)
160
- end
161
-
162
- it "should return the correct number" do
163
- MultiXml.parse(@xml)['id'].should == 1
164
- end
165
- end
166
-
167
- context "when key contains _id" do
168
- before do
169
- pending
170
- @xml = '<tag_id>1</tag_id>'
171
- end
172
-
173
- it "should return a Fixnum" do
174
- MultiXml.parse(@xml)['tag_id'].should be_a(Fixnum)
175
- end
176
-
177
- it "should return the correct number" do
178
- MultiXml.parse(@xml)['tag_id'].should == 1
179
- end
180
- end
181
-
182
- context "with an attribute type=\"boolean\"" do
183
- %w(true false).each do |boolean|
184
- context "when #{boolean}" do
185
- it "should return #{boolean}" do
186
- xml = "<tag type=\"boolean\">#{boolean}</tag>"
187
- MultiXml.parse(xml)['tag'].should instance_eval("be_#{boolean}")
188
- end
189
- end
190
- end
191
-
192
- context "when 1" do
193
- before do
194
- @xml = '<tag type="boolean">1</tag>'
195
- end
196
-
197
- it "should return true" do
198
- MultiXml.parse(@xml)['tag'].should be_true
199
- end
200
- end
201
-
202
- context "when 0" do
203
- before do
204
- @xml = '<tag type="boolean">0</tag>'
205
- end
206
-
207
- it "should return false" do
208
- MultiXml.parse(@xml)['tag'].should be_false
209
- end
210
- end
211
- end
212
-
213
- context "with an attribute type=\"integer\"" do
214
- context "with a positive integer" do
215
- before do
216
- @xml = '<tag type="integer">1</tag>'
217
- end
218
-
219
- it "should return a Fixnum" do
220
- MultiXml.parse(@xml)['tag'].should be_a(Fixnum)
221
- end
222
-
223
- it "should return a positive number" do
224
- MultiXml.parse(@xml)['tag'].should > 0
225
- end
226
-
227
- it "should return the correct number" do
228
- MultiXml.parse(@xml)['tag'].should == 1
229
- end
230
- end
231
-
232
- context "with a negative integer" do
233
- before do
234
- @xml = '<tag type="integer">-1</tag>'
235
- end
236
-
237
- it "should return a Fixnum" do
238
- MultiXml.parse(@xml)['tag'].should be_a(Fixnum)
239
- end
240
-
241
- it "should return a negative number" do
242
- MultiXml.parse(@xml)['tag'].should < 0
243
- end
244
-
245
- it "should return the correct number" do
246
- MultiXml.parse(@xml)['tag'].should == -1
247
- end
248
- end
249
- end
250
-
251
- context "with an attribute type=\"string\"" do
252
- before do
253
- @xml = '<tag type="string"></tag>'
254
- end
255
-
256
- it "should return a String" do
257
- MultiXml.parse(@xml)['tag'].should be_a(String)
258
- end
259
-
260
- it "should return the correct string" do
261
- MultiXml.parse(@xml)['tag'].should == ""
262
- end
263
- end
264
-
265
- context "with an attribute type=\"date\"" do
266
- before do
267
- @xml = '<tag type="date">1970-01-01</tag>'
268
- end
269
-
270
- it "should return a Date" do
271
- MultiXml.parse(@xml)['tag'].should be_a(Date)
272
- end
273
-
274
- it "should return the correct date" do
275
- MultiXml.parse(@xml)['tag'].should == Date.parse('1970-01-01')
276
- end
277
- end
278
-
279
- context "with an attribute type=\"datetime\"" do
280
- before do
281
- @xml = '<tag type="datetime">1970-01-01 00:00</tag>'
282
- end
283
-
284
- it "should return a Time" do
285
- MultiXml.parse(@xml)['tag'].should be_a(Time)
286
- end
287
-
288
- it "should return the correct time" do
289
- MultiXml.parse(@xml)['tag'].should == Time.parse('1970-01-01 00:00')
290
- end
291
- end
292
-
293
- context "with an attribute type=\"dateTime\"" do
294
- before do
295
- @xml = '<tag type="datetime">1970-01-01 00:00</tag>'
296
- end
297
-
298
- it "should return a Time" do
299
- MultiXml.parse(@xml)['tag'].should be_a(Time)
300
- end
301
-
302
- it "should return the correct time" do
303
- MultiXml.parse(@xml)['tag'].should == Time.parse('1970-01-01 00:00')
304
- end
305
- end
306
-
307
- context "with an attribute type=\"double\"" do
308
- before do
309
- @xml = '<tag type="double">3.14159265358979</tag>'
310
- end
311
-
312
- it "should return a Float" do
313
- MultiXml.parse(@xml)['tag'].should be_a(Float)
314
- end
315
-
316
- it "should return the correct number" do
317
- MultiXml.parse(@xml)['tag'].should == 3.14159265358979
318
- end
319
- end
320
-
321
- context "with an attribute type=\"decimal\"" do
322
- before do
323
- @xml = '<tag type="decimal">3.14159265358979323846264338327950288419716939937510</tag>'
324
- end
325
-
326
- it "should return a BigDecimal" do
327
- MultiXml.parse(@xml)['tag'].should be_a(BigDecimal)
328
- end
329
-
330
- it "should return the correct number" do
331
- MultiXml.parse(@xml)['tag'].should == 3.14159265358979323846264338327950288419716939937510
332
- end
333
- end
334
-
335
- context "with an attribute type=\"base64Binary\"" do
336
- before do
337
- @xml = '<tag type="base64Binary">aW1hZ2UucG5n</tag>'
338
- end
339
-
340
- it "should return a String" do
341
- MultiXml.parse(@xml)['tag'].should be_a(String)
342
- end
343
-
344
- it "should return the correct string" do
345
- MultiXml.parse(@xml)['tag'].should == "image.png"
346
- end
347
- end
348
-
349
- context "with an attribute type=\"yaml\"" do
350
- before do
351
- @xml = "<tag type=\"yaml\">--- \n1: should return an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</tag>"
352
- end
353
-
354
- it "should return a Hash" do
355
- MultiXml.parse(@xml)['tag'].should be_a(Hash)
356
- end
357
-
358
- it "should return the correctly parsed YAML" do
359
- MultiXml.parse(@xml)['tag'].should == {:message => "Have a nice day", 1 => "should return an integer", "array" => [{"should-have-dashes" => true, "should_have_underscores" => true}]}
360
- end
361
- end
362
-
363
- context "with an attribute type=\"file\"" do
364
- before do
365
- @xml = '<tag type="file" name="data.txt" content_type="text/plain">ZGF0YQ==</tag>'
366
- end
367
-
368
- it "should return a StringIO" do
369
- MultiXml.parse(@xml)['tag'].should be_a(StringIO)
370
- end
371
-
372
- it "should be decoded correctly" do
373
- MultiXml.parse(@xml)['tag'].string.should == 'data'
374
- end
375
-
376
- it "should have the correct file name" do
377
- MultiXml.parse(@xml)['tag'].original_filename.should == 'data.txt'
378
- end
379
-
380
- it "should have the correct content type" do
381
- MultiXml.parse(@xml)['tag'].content_type.should == 'text/plain'
382
- end
383
-
384
- context "with missing name and content type" do
385
- before do
386
- @xml = '<tag type="file">ZGF0YQ==</tag>'
387
- end
388
-
389
- it "should return a StringIO" do
390
- MultiXml.parse(@xml)['tag'].should be_a(StringIO)
391
- end
392
-
393
- it "should be decoded correctly" do
394
- MultiXml.parse(@xml)['tag'].string.should == 'data'
395
- end
396
-
397
- it "should have the default file name" do
398
- MultiXml.parse(@xml)['tag'].original_filename.should == 'untitled'
399
- end
400
-
401
- it "should have the default content type" do
402
- MultiXml.parse(@xml)['tag'].content_type.should == 'application/octet-stream'
403
- end
404
- end
405
- end
406
-
407
- context "with an attribute type=\"array\"" do
408
- before do
409
- @xml = '<users type="array"><user>Erik Michaels-Ober</user><user>Wynn Netherland</user></users>'
410
- end
411
-
412
- it "should return an Array" do
413
- MultiXml.parse(@xml)['users'].should be_a(Array)
414
- end
415
-
416
- it "should return the correct array" do
417
- MultiXml.parse(@xml)['users'].should == ["Erik Michaels-Ober", "Wynn Netherland"]
418
- end
419
- end
420
-
421
- %w(integer boolean date datetime yaml file).each do |type|
422
- context "with an empty attribute type=\"#{type}\"" do
423
- before do
424
- @xml = "<tag type=\"#{type}\"/>"
425
- end
426
-
427
- it "should return nil" do
428
- MultiXml.parse(@xml)['tag'].should be_nil
429
- end
430
- end
431
- end
432
-
433
- context "with an empty attribute type=\"array\"" do
434
- before do
435
- @xml = '<tag type="array"/>'
436
- end
437
-
438
- it "should return an empty Array" do
439
- MultiXml.parse(@xml)['tag'].should == []
440
- end
441
-
442
- context "with whitespace" do
443
- before do
444
- @xml = '<tag type="array"> </tag>'
445
- end
446
-
447
- it "should return an empty Array" do
448
- MultiXml.parse(@xml)['tag'].should == []
449
- end
450
- end
451
- end
452
-
453
- context "with XML entities" do
454
- before do
455
- @xml_entities = {
456
- "<" => "&lt;",
457
- ">" => "&gt;",
458
- '"' => "&quot;",
459
- "'" => "&apos;",
460
- "&" => "&amp;"
461
- }
462
- end
463
-
464
- context "in content" do
465
- it "should return unescaped XML entities" do
466
- @xml_entities.each do |key, value|
467
- xml = "<tag>#{value}</tag>"
468
- MultiXml.parse(xml)['tag'].should == key
469
- end
470
- end
471
- end
472
-
473
- context "in attribute" do
474
- it "should return unescaped XML entities" do
475
- @xml_entities.each do |key, value|
476
- xml = "<tag attribute=\"#{value}\"/>"
477
- MultiXml.parse(xml)['tag']['attribute'].should == key
478
- end
479
- end
480
- end
481
- end
482
-
483
- context "with dasherized tag" do
484
- before do
485
- @xml = '<tag-1/>'
486
- end
487
-
488
- it "should return undasherize tag" do
489
- MultiXml.parse(@xml).keys.should include('tag_1')
490
- end
491
- end
492
-
493
- context "with dasherized attribute" do
494
- before do
495
- @xml = '<tag attribute-1="1"></tag>'
496
- end
497
-
498
- it "should return undasherize attribute" do
499
- MultiXml.parse(@xml)['tag'].keys.should include('attribute_1')
500
- end
501
- end
502
-
503
- context "with children" do
504
- context "with attributes" do
505
- before do
506
- @xml = '<users><user name="Erik Michaels-Ober"/></users>'
507
- end
508
-
509
- it "should return the correct attributes" do
510
- MultiXml.parse(@xml)['users']['user']['name'].should == "Erik Michaels-Ober"
511
- end
512
- end
513
-
514
- context "with text" do
515
- before do
516
- @xml = '<user><name>Erik Michaels-Ober</name></user>'
517
- end
518
-
519
- it "should return the correct text" do
520
- MultiXml.parse(@xml)['user']['name'].should == "Erik Michaels-Ober"
521
- end
522
- end
523
-
524
- context "with an unrecognized attribute type" do
525
- before do
526
- @xml = '<user type="admin"><name>Erik Michaels-Ober</name></user>'
527
- end
528
-
529
- it "should pass through the type" do
530
- MultiXml.parse(@xml)['user']['type'].should == 'admin'
531
- end
532
- end
533
-
534
- context "with newlines and whitespace" do
535
- before do
536
- @xml = <<-XML
537
- <user>
538
- <name>Erik Michaels-Ober</name>
539
- </user>
540
- XML
541
- end
542
-
543
- it "should parse correctly" do
544
- MultiXml.parse(@xml).should == {"user" => {"name" => "Erik Michaels-Ober"}}
545
- end
546
- end
547
-
548
- # Babies having babies
549
- context "with children" do
550
- before do
551
- @xml = '<users><user name="Erik Michaels-Ober"><status text="Hello"/></user></users>'
552
- end
553
-
554
- it "should parse correctly" do
555
- MultiXml.parse(@xml).should == {"users" => {"user" => {"name" => "Erik Michaels-Ober", "status" => {"text" => "Hello"}}}}
556
- end
557
- end
558
- end
559
-
560
- context "with sibling children" do
561
- before do
562
- @xml = '<users><user>Erik Michaels-Ober</user><user>Wynn Netherland</user></users>'
563
- end
564
-
565
- it "should return an Array" do
566
- MultiXml.parse(@xml)['users']['user'].should be_a(Array)
567
- end
568
-
569
- it "should parse correctly" do
570
- MultiXml.parse(@xml).should == {"users" => {"user" => ["Erik Michaels-Ober", "Wynn Netherland"]}}
571
- end
572
- end
573
- end
28
+ [['LibXML', 'libxml'],
29
+ ['REXML', 'rexml/document'],
30
+ ['Nokogiri', 'nokogiri']].each do |parser|
31
+ begin
32
+ require parser.last
33
+ context "#{parser.first} parser" do
34
+ it_should_behave_like "a parser", parser.first
574
35
  end
36
+ rescue LoadError => e
37
+ puts "Tests not run for #{parser.first} due to a LoadError"
575
38
  end
576
39
  end
577
40
  end