sax-machine-patched 0.2.0.rc2

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.
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ class A
4
+
5
+ SAXMachine.configure(A) do |c|
6
+ c.element :title
7
+ end
8
+
9
+ end
10
+
11
+ class B < A
12
+
13
+ SAXMachine.configure(B) do |c|
14
+ c.element :b
15
+ end
16
+
17
+ end
18
+
19
+ class C < B
20
+
21
+ SAXMachine.configure(C) do |c|
22
+ c.element :c
23
+ end
24
+
25
+ end
26
+
27
+ describe "SAXMachine configure" do
28
+ before do
29
+ xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
30
+ @a = A.new
31
+ @a.parse xml
32
+ @b = B.new
33
+ @b.parse xml
34
+ @c = C.new
35
+ @c.parse xml
36
+ end
37
+ it { @a.should be_a(A) }
38
+ it { @a.should_not be_a(B) }
39
+ it { @a.should be_a(SAXMachine) }
40
+ it { @a.title.should == "Test" }
41
+ it { @b.should be_a(A) }
42
+ it { @b.should be_a(B) }
43
+ it { @b.should be_a(SAXMachine) }
44
+ it { @b.title.should == "Test" }
45
+ it { @b.b.should == "Matched!" }
46
+ it { @c.should be_a(A) }
47
+ it { @c.should be_a(B) }
48
+ it { @c.should be_a(C) }
49
+ it { @c.should be_a(SAXMachine) }
50
+ it { @c.title.should == "Test" }
51
+ it { @c.b.should == "Matched!" }
52
+ it { @c.c.should == "And Again" }
53
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ class A
4
+ include SAXMachine
5
+ element :title
6
+ end
7
+
8
+ class B < A
9
+ element :b
10
+ end
11
+
12
+ class C < B
13
+ element :c
14
+ end
15
+
16
+ describe "SAXMachine inheritance" do
17
+ before do
18
+ xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
19
+ @a = A.new
20
+ @a.parse xml
21
+ @b = B.new
22
+ @b.parse xml
23
+ @c = C.new
24
+ @c.parse xml
25
+ end
26
+ it { @a.should be_a(A) }
27
+ it { @a.should_not be_a(B) }
28
+ it { @a.should be_a(SAXMachine) }
29
+ it { @a.title.should == "Test" }
30
+ it { @b.should be_a(A) }
31
+ it { @b.should be_a(B) }
32
+ it { @b.should be_a(SAXMachine) }
33
+ it { @b.title.should == "Test" }
34
+ it { @b.b.should == "Matched!" }
35
+ it { @c.should be_a(A) }
36
+ it { @c.should be_a(B) }
37
+ it { @c.should be_a(C) }
38
+ it { @c.should be_a(SAXMachine) }
39
+ it { @c.title.should == "Test" }
40
+ it { @c.b.should == "Matched!" }
41
+ it { @c.c.should == "And Again" }
42
+ end
@@ -0,0 +1,838 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "SAXMachine" do
4
+ describe "element" do
5
+ describe "when parsing a single element" do
6
+ before :each do
7
+ @klass = Class.new do
8
+ include SAXMachine
9
+ element :title
10
+ end
11
+ end
12
+
13
+ it "should provide mass assignment through initialize method" do
14
+ document = @klass.new(title: 'Title')
15
+ document.title.should == 'Title'
16
+ end
17
+
18
+ it "should provide an accessor" do
19
+ document = @klass.new
20
+ document.title = "Title"
21
+ document.title.should == "Title"
22
+ end
23
+
24
+ it "should allow introspection of the elements" do
25
+ @klass.column_names.should =~ [:title]
26
+ end
27
+
28
+ it "should not overwrite the getter is there is already one present" do
29
+ @klass = Class.new do
30
+ def title
31
+ "#{@title} ***"
32
+ end
33
+
34
+ include SAXMachine
35
+ element :title
36
+ end
37
+ document = @klass.new
38
+ document.title = "Title"
39
+ document.title.should == "Title ***"
40
+ end
41
+
42
+ it "should not overwrite the setter if there is already one present" do
43
+ @klass = Class.new do
44
+ def title=(val)
45
+ @title = "#{val} **"
46
+ end
47
+
48
+ include SAXMachine
49
+ element :title
50
+ end
51
+ document = @klass.new
52
+ document.title = "Title"
53
+ document.title.should == "Title **"
54
+ end
55
+ describe "the class attribute" do
56
+ before(:each) do
57
+ @klass = Class.new do
58
+ include SAXMachine
59
+ element :date, :class => DateTime
60
+ end
61
+ @document = @klass.new
62
+ @document.date = Time.now.iso8601
63
+ end
64
+ it "should be available" do
65
+ @klass.data_class(:date).should == DateTime
66
+ end
67
+
68
+ it "should handle an integer class" do
69
+ @klass = Class.new do
70
+ include SAXMachine
71
+ element :number, :class => Integer
72
+ end
73
+ document = @klass.parse("<number>5</number>")
74
+ document.number.should == 5
75
+ end
76
+
77
+ it "should handle an float class" do
78
+ @klass = Class.new do
79
+ include SAXMachine
80
+ element :number, :class => Float
81
+ end
82
+ document = @klass.parse("<number>5.5</number>")
83
+ document.number.should == 5.5
84
+ end
85
+
86
+ it "should handle an string class" do
87
+ @klass = Class.new do
88
+ include SAXMachine
89
+ element :number, :class => String
90
+ end
91
+ document = @klass.parse("<number>5.5</number>")
92
+ document.number.should == "5.5"
93
+ end
94
+
95
+ it "should handle a time class" do
96
+ @klass = Class.new do
97
+ include SAXMachine
98
+ element :time, :class => Time
99
+ end
100
+ document = @klass.parse("<time>1994-02-04T06:20:00Z</time>")
101
+ document.time.should == Time.utc(1994, 2, 4, 6, 20, 0, 0)
102
+ end
103
+
104
+ end
105
+ describe "the required attribute" do
106
+ it "should be available" do
107
+ @klass = Class.new do
108
+ include SAXMachine
109
+ element :date, :required => true
110
+ end
111
+ @klass.required?(:date).should be_true
112
+ end
113
+ end
114
+
115
+ it "should not overwrite the accessor when the element is not present" do
116
+ document = @klass.new
117
+ document.title = "Title"
118
+ document.parse("<foo></foo>")
119
+ document.title.should == "Title"
120
+ end
121
+
122
+ it "should overwrite the value when the element is present" do
123
+ document = @klass.new
124
+ document.title = "Old title"
125
+ document.parse("<title>New title</title>")
126
+ document.title.should == "New title"
127
+ end
128
+
129
+ it "should save the element text into an accessor" do
130
+ document = @klass.parse("<title>My Title</title>")
131
+ document.title.should == "My Title"
132
+ end
133
+
134
+ if RUBY_VERSION >= "1.9.0"
135
+ it "should keep the document encoding for elements" do
136
+ data = "<title>My Title</title>"
137
+ data.encode!("utf-8")
138
+
139
+ document = @klass.parse(data)
140
+ document.title.encoding.should == data.encoding
141
+ end
142
+ end
143
+
144
+ it "should save cdata into an accessor" do
145
+ document = @klass.parse("<title><![CDATA[A Title]]></title>")
146
+ document.title.should == "A Title"
147
+ end
148
+
149
+ it "should save the element text into an accessor when there are multiple elements" do
150
+ document = @klass.parse("<xml><title>My Title</title><foo>bar</foo></xml>")
151
+ document.title.should == "My Title"
152
+ end
153
+
154
+ it "should save the first element text when there are multiple of the same element" do
155
+ document = @klass.parse("<xml><title>My Title</title><title>bar</title></xml>")
156
+ document.title.should == "My Title"
157
+
158
+ end
159
+ end
160
+
161
+ describe "when parsing multiple elements" do
162
+ before :each do
163
+ @klass = Class.new do
164
+ include SAXMachine
165
+ element :title
166
+ element :name
167
+ end
168
+ end
169
+
170
+ it "should save the element text for a second tag" do
171
+ document = @klass.parse("<xml><title>My Title</title><name>Paul</name></xml>")
172
+ document.name.should == "Paul"
173
+ document.title.should == "My Title"
174
+ end
175
+
176
+
177
+ it "should not overwrite the getter is there is already one present" do
178
+ @klass = Class.new do
179
+ def items
180
+ []
181
+ end
182
+
183
+ include SAXMachine
184
+ elements :items
185
+ end
186
+ document = @klass.new
187
+ document.items = [1, 2, 3, 4]
188
+ document.items.should == []
189
+ end
190
+
191
+ it "should not overwrite the setter if there is already one present" do
192
+ @klass = Class.new do
193
+ def items=(val)
194
+ @items = [1, *val]
195
+ end
196
+
197
+ include SAXMachine
198
+ elements :items
199
+ end
200
+ document = @klass.new
201
+ document.items = [2, 3]
202
+ document.items.should == [1, 2, 3]
203
+ end
204
+
205
+ end
206
+
207
+ describe "when using options for parsing elements" do
208
+ describe "using the 'as' option" do
209
+ before :each do
210
+ @klass = Class.new do
211
+ include SAXMachine
212
+ element :description, :as => :summary
213
+ end
214
+ end
215
+
216
+ it "should provide an accessor using the 'as' name" do
217
+ document = @klass.new
218
+ document.summary = "a small summary"
219
+ document.summary.should == "a small summary"
220
+ end
221
+
222
+ it "should save the element text into the 'as' accessor" do
223
+ document = @klass.parse("<description>here is a description</description>")
224
+ document.summary.should == "here is a description"
225
+ end
226
+ end
227
+
228
+ describe "using the :with option" do
229
+ describe "and the :value option" do
230
+ before :each do
231
+ @klass = Class.new do
232
+ include SAXMachine
233
+ element :link, :value => :href, :with => {:foo => "bar"}
234
+ end
235
+ end
236
+
237
+ it "should save the value of a matching element" do
238
+ document = @klass.parse("<link href='test' foo='bar'>asdf</link>")
239
+ document.link.should == "test"
240
+ end
241
+
242
+ it "should save the value of the first matching element" do
243
+ document = @klass.parse("<xml><link href='first' foo='bar' /><link href='second' foo='bar' /></xml>")
244
+ document.link.should == "first"
245
+ end
246
+
247
+ describe "and the :as option" do
248
+ before :each do
249
+ @klass = Class.new do
250
+ include SAXMachine
251
+ element :link, :value => :href, :as => :url, :with => {:foo => "bar"}
252
+ element :link, :value => :href, :as => :second_url, :with => {:asdf => "jkl"}
253
+ end
254
+ end
255
+
256
+ it "should save the value of the first matching element" do
257
+ document = @klass.parse("<xml><link href='first' foo='bar' /><link href='second' asdf='jkl' /><link href='second' foo='bar' /></xml>")
258
+ document.url.should == "first"
259
+ document.second_url.should == "second"
260
+ end
261
+
262
+ end
263
+ end
264
+
265
+ describe "with only one element" do
266
+ before :each do
267
+ @klass = Class.new do
268
+ include SAXMachine
269
+ element :link, :with => {:foo => "bar"}
270
+ end
271
+ end
272
+
273
+ it "should save the text of an element that has matching attributes" do
274
+ document = @klass.parse("<link foo=\"bar\">match</link>")
275
+ document.link.should == "match"
276
+ end
277
+
278
+ it "should not save the text of an element that doesn't have matching attributes" do
279
+ document = @klass.parse("<link>no match</link>")
280
+ document.link.should be_nil
281
+ end
282
+
283
+ it "should save the text of an element that has matching attributes when it is the second of that type" do
284
+ document = @klass.parse("<xml><link>no match</link><link foo=\"bar\">match</link></xml>")
285
+ document.link.should == "match"
286
+
287
+ end
288
+
289
+ it "should save the text of an element that has matching attributes plus a few more" do
290
+ document = @klass.parse("<xml><link>no match</link><link asdf='jkl' foo='bar'>match</link>")
291
+ document.link.should == "match"
292
+ end
293
+ end
294
+
295
+ describe "with multiple elements of same tag" do
296
+ before :each do
297
+ @klass = Class.new do
298
+ include SAXMachine
299
+ element :link, :as => :first, :with => {:foo => "bar"}
300
+ element :link, :as => :second, :with => {:asdf => "jkl"}
301
+ end
302
+ end
303
+
304
+ it "should match the first element" do
305
+ document = @klass.parse("<xml><link>no match</link><link foo=\"bar\">first match</link><link>no match</link></xml>")
306
+ document.first.should == "first match"
307
+ end
308
+
309
+ it "should match the second element" do
310
+ document = @klass.parse("<xml><link>no match</link><link foo='bar'>first match</link><link asdf='jkl'>second match</link><link>hi</link></xml>")
311
+ document.second.should == "second match"
312
+ end
313
+ end
314
+
315
+ describe "with only one element as a regular expression" do
316
+ before :each do
317
+ @klass = Class.new do
318
+ include SAXMachine
319
+ element :link, :with => {:foo => /ar$/}
320
+ end
321
+ end
322
+
323
+ it "should save the text of an element that has matching attributes" do
324
+ document = @klass.parse("<link foo=\"bar\">match</link>")
325
+ document.link.should == "match"
326
+ end
327
+
328
+ it "should not save the text of an element that doesn't have matching attributes" do
329
+ document = @klass.parse("<link>no match</link>")
330
+ document.link.should be_nil
331
+ end
332
+
333
+ it "should save the text of an element that has matching attributes when it is the second of that type" do
334
+ document = @klass.parse("<xml><link>no match</link><link foo=\"bar\">match</link></xml>")
335
+ document.link.should == "match"
336
+ end
337
+
338
+ it "should save the text of an element that has matching attributes plus a few more" do
339
+ document = @klass.parse("<xml><link>no match</link><link asdf='jkl' foo='bar'>match</link>")
340
+ document.link.should == "match"
341
+ end
342
+ end
343
+ end # using the 'with' option
344
+
345
+ describe "using the 'value' option" do
346
+ before :each do
347
+ @klass = Class.new do
348
+ include SAXMachine
349
+ element :link, :value => :foo
350
+ end
351
+ end
352
+
353
+ it "should save the attribute value" do
354
+ document = @klass.parse("<link foo='test'>hello</link>")
355
+ document.link.should == 'test'
356
+ end
357
+
358
+ it "should save the attribute value when there is no text enclosed by the tag" do
359
+ document = @klass.parse("<link foo='test'></link>")
360
+ document.link.should == 'test'
361
+ end
362
+
363
+ it "should save the attribute value when the tag close is in the open" do
364
+ document = @klass.parse("<link foo='test'/>")
365
+ document.link.should == 'test'
366
+ end
367
+
368
+ it "should save two different attribute values on a single tag" do
369
+ @klass = Class.new do
370
+ include SAXMachine
371
+ element :link, :value => :foo, :as => :first
372
+ element :link, :value => :bar, :as => :second
373
+ end
374
+ document = @klass.parse("<link foo='foo value' bar='bar value'></link>")
375
+ document.first.should == "foo value"
376
+ document.second.should == "bar value"
377
+ end
378
+
379
+ it "should not fail if one of the attribute hasn't been defined" do
380
+ @klass = Class.new do
381
+ include SAXMachine
382
+ element :link, :value => :foo, :as => :first
383
+ element :link, :value => :bar, :as => :second
384
+ end
385
+ document = @klass.parse("<link foo='foo value'></link>")
386
+ document.first.should == "foo value"
387
+ document.second.should be_nil
388
+ end
389
+ end
390
+
391
+ describe "when desiring both the content and attributes of an element" do
392
+ before :each do
393
+ @klass = Class.new do
394
+ include SAXMachine
395
+ element :link
396
+ element :link, :value => :foo, :as => :link_foo
397
+ element :link, :value => :bar, :as => :link_bar
398
+ end
399
+ end
400
+
401
+ it "should parse the element and attribute values" do
402
+ document = @klass.parse("<link foo='test1' bar='test2'>hello</link>")
403
+ document.link.should == 'hello'
404
+ document.link_foo.should == 'test1'
405
+ document.link_bar.should == 'test2'
406
+ end
407
+ end
408
+
409
+ end
410
+ end
411
+
412
+ describe "elements" do
413
+ describe "when parsing multiple elements" do
414
+ before :each do
415
+ @klass = Class.new do
416
+ include SAXMachine
417
+ elements :entry, :as => :entries
418
+ end
419
+ end
420
+
421
+ it "should provide a collection accessor" do
422
+ document = @klass.new
423
+ document.entries << :foo
424
+ document.entries.should == [:foo]
425
+ end
426
+
427
+ it "should parse a single element" do
428
+ document = @klass.parse("<entry>hello</entry>")
429
+ document.entries.should == ["hello"]
430
+ end
431
+
432
+ it "should parse multiple elements" do
433
+ document = @klass.parse("<xml><entry>hello</entry><entry>world</entry></xml>")
434
+ document.entries.should == ["hello", "world"]
435
+ end
436
+
437
+ it "should parse multiple elements when taking an attribute value" do
438
+ attribute_klass = Class.new do
439
+ include SAXMachine
440
+ elements :entry, :as => :entries, :value => :foo
441
+ end
442
+ doc = attribute_klass.parse("<xml><entry foo='asdf' /><entry foo='jkl' /></xml>")
443
+ doc.entries.should == ["asdf", "jkl"]
444
+ end
445
+ end
446
+
447
+ describe "when using the with and class options" do
448
+ before :each do
449
+ class Bar
450
+ include SAXMachine
451
+ element :title
452
+ end
453
+
454
+ class Foo
455
+ include SAXMachine
456
+ element :title
457
+ end
458
+
459
+ class Item
460
+ include SAXMachine
461
+
462
+ end
463
+ @klass = Class.new do
464
+ include SAXMachine
465
+ elements :item, :as => :items, :with => {:type => 'Bar'}, :class => Bar
466
+ elements :item, :as => :items, :with => {:type => /Foo/}, :class => Foo
467
+ end
468
+ end
469
+
470
+ it "should cast into the correct class" do
471
+ document = @klass.parse("<items><item type=\"Bar\"><title>Bar title</title></item><item type=\"Foo\"><title>Foo title</title></item></items>")
472
+ document.items.size.should == 2
473
+ document.items.first.should be_a(Bar)
474
+ document.items.first.title.should == "Bar title"
475
+ document.items.last.should be_a(Foo)
476
+ document.items.last.title.should == "Foo title"
477
+ end
478
+ end
479
+
480
+ describe "when using the class option" do
481
+ before :each do
482
+ class Foo
483
+ include SAXMachine
484
+ element :title
485
+ end
486
+ @klass = Class.new do
487
+ include SAXMachine
488
+ elements :entry, :as => :entries, :class => Foo
489
+ end
490
+ end
491
+
492
+ it "should parse a single element with children" do
493
+ document = @klass.parse("<entry><title>a title</title></entry>")
494
+ document.entries.size.should == 1
495
+ document.entries.first.title.should == "a title"
496
+ end
497
+
498
+ it "should parse multiple elements with children" do
499
+ document = @klass.parse("<xml><entry><title>title 1</title></entry><entry><title>title 2</title></entry></xml>")
500
+ document.entries.size.should == 2
501
+ document.entries.first.title.should == "title 1"
502
+ document.entries.last.title.should == "title 2"
503
+ end
504
+
505
+ it "should not parse a top level element that is specified only in a child" do
506
+ document = @klass.parse("<xml><title>no parse</title><entry><title>correct title</title></entry></xml>")
507
+ document.entries.size.should == 1
508
+ document.entries.first.title.should == "correct title"
509
+ end
510
+
511
+ it "should parse elements, and make attributes and inner text available" do
512
+ class Related
513
+ include SAXMachine
514
+ element 'related', :as=>:item
515
+ element 'related', :as=>:attr, :value=>'attr'
516
+ end
517
+ class Foo
518
+ elements 'related', :as=>'items', :class=>Related
519
+ end
520
+
521
+ doc = Foo.parse(%{<xml><collection><related attr='baz'>something</related><related>somethingelse</related></collection></xml>})
522
+ doc.items.first.should_not be_nil
523
+ doc.items.size.should == 2
524
+ doc.items.first.item.should == 'something'
525
+ doc.items.last.item.should == 'somethingelse'
526
+ end
527
+
528
+ it "should parse out an attribute value from the tag that starts the collection" do
529
+ class Foo
530
+ element :entry, :value => :href, :as => :url
531
+ end
532
+ document = @klass.parse("<xml><entry href='http://pauldix.net'><title>paul</title></entry></xml>")
533
+ document.entries.size.should == 1
534
+ document.entries.first.title.should == "paul"
535
+ document.entries.first.url.should == "http://pauldix.net"
536
+ end
537
+ end
538
+ end
539
+
540
+ describe "when dealing with element names containing dashes" do
541
+ it 'should automatically convert dashes to underscores' do
542
+ class Dashes
543
+ include SAXMachine
544
+ element :dashed_element
545
+ end
546
+
547
+ parsed = Dashes.parse('<dashed-element>Text</dashed-element>')
548
+ parsed.dashed_element.should eq "Text"
549
+ end
550
+ end
551
+
552
+ describe "full example" do
553
+ before :each do
554
+ @xml = File.read('spec/sax-machine/atom.xml')
555
+ class AtomEntry
556
+ include SAXMachine
557
+ element :title
558
+ element :name, :as => :author
559
+ element "feedburner:origLink", :as => :url
560
+ element :link, :as => :alternate, :value => :href, :with => {:type => "text/html", :rel => "alternate"}
561
+ element :summary
562
+ element :content
563
+ element :published
564
+ end
565
+
566
+ class Atom
567
+ include SAXMachine
568
+ element :title
569
+ element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
570
+ element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
571
+ elements :entry, :as => :entries, :class => AtomEntry
572
+ end
573
+ end # before
574
+
575
+ it "should parse the url" do
576
+ f = Atom.parse(@xml)
577
+ f.url.should == "http://www.pauldix.net/"
578
+ end
579
+
580
+ it "should parse entry url" do
581
+ f = Atom.parse(@xml)
582
+ f.entries.first.url.should == "http://www.pauldix.net/2008/09/marshal-data-to.html?param1=1&param2=2"
583
+ f.entries.first.alternate.should == "http://feeds.feedburner.com/~r/PaulDixExplainsNothing/~3/383536354/marshal-data-to.html?param1=1&param2=2"
584
+ end
585
+ end
586
+
587
+ describe "parsing a tree" do
588
+ before do
589
+ @xml = %[
590
+ <categories>
591
+ <category id="1">
592
+ <title>First</title>
593
+ <categories>
594
+ <category id="2">
595
+ <title>Second</title>
596
+ </category>
597
+ </categories>
598
+ </category>
599
+ </categories>
600
+ ]
601
+ class CategoryCollection;
602
+ end
603
+ class Category
604
+ include SAXMachine
605
+ attr_accessor :id
606
+ element :category, :value => :id, :as => :id
607
+ element :title
608
+ element :categories, :as => :collection, :class => CategoryCollection
609
+ ancestor :ancestor
610
+ end
611
+ class CategoryCollection
612
+ include SAXMachine
613
+ elements :category, :as => :categories, :class => Category
614
+ end
615
+ @collection = CategoryCollection.parse(@xml)
616
+ end
617
+
618
+ it "should parse the first category" do
619
+ @collection.categories.first.id.should == "1"
620
+ @collection.categories.first.title.should == "First"
621
+ @collection.categories.first.ancestor.should == @collection
622
+ end
623
+
624
+ it "should parse the nested category" do
625
+ @collection.categories.first.collection.categories.first.id.should == "2"
626
+ @collection.categories.first.collection.categories.first.title.should == "Second"
627
+ end
628
+ end
629
+
630
+ describe "parsing a tree without a collection class" do
631
+ before do
632
+ @xml = %[
633
+ <categories>
634
+ <category id="1">
635
+ <title>First</title>
636
+ <categories>
637
+ <category id="2">
638
+ <title>Second</title>
639
+ </category>
640
+ </categories>
641
+ </category>
642
+ </categories>
643
+ ]
644
+ class CategoryTree
645
+ include SAXMachine
646
+ attr_accessor :id
647
+ element :category, :value => :id, :as => :id
648
+ element :title
649
+ elements :category, :as => :categories, :class => CategoryTree
650
+ end
651
+ @collection = CategoryTree.parse(@xml)
652
+ end
653
+
654
+ it "should parse the first category" do
655
+ @collection.categories.first.id.should == "1"
656
+ @collection.categories.first.title.should == "First"
657
+ end
658
+
659
+ it "should parse the nested category" do
660
+ @collection.categories.first.categories.first.id.should == "2"
661
+ @collection.categories.first.categories.first.title.should == "Second"
662
+ end
663
+ end
664
+
665
+ describe "with element deeper inside the xml structure" do
666
+ before do
667
+ @xml = %[
668
+ <item id="1">
669
+ <texts>
670
+ <title>Hello</title>
671
+ </texts>
672
+ </item>
673
+ ]
674
+ @klass = Class.new do
675
+ include SAXMachine
676
+ attr_accessor :id
677
+ element :item, :value => "id", :as => :id
678
+ element :title
679
+ end
680
+ @item = @klass.parse(@xml)
681
+ end
682
+
683
+ it "should have an id" do
684
+ @item.id.should == "1"
685
+ end
686
+
687
+ it "should have a title" do
688
+ @item.title.should == "Hello"
689
+ end
690
+ end
691
+
692
+ describe "with config to pull multiple attributes" do
693
+ before do
694
+ @xml = %[
695
+ <item id="1">
696
+ <author name="John Doe" role="writer" />
697
+ </item>
698
+ ]
699
+ class AuthorElement
700
+ include SAXMachine
701
+ attribute :name
702
+ attribute :role
703
+ end
704
+ class ItemElement
705
+ include SAXMachine
706
+ element :author, :class => AuthorElement
707
+ end
708
+ @item = ItemElement.parse(@xml)
709
+ end
710
+
711
+ it 'should have the child element' do
712
+ @item.author.should_not be_nil
713
+ end
714
+
715
+ it 'should have the author name' do
716
+ @item.author.name.should == 'John Doe'
717
+ end
718
+
719
+ it 'should have the author role' do
720
+ @item.author.role.should == 'writer'
721
+ end
722
+ end
723
+
724
+ describe "with multiple elements and multiple attributes" do
725
+ before do
726
+ @xml = %[
727
+ <item id="1">
728
+ <author name="John Doe" role="writer" />
729
+ <author name="Jane Doe" role="artist" />
730
+ </item>
731
+ ]
732
+ class AuthorElement2
733
+ include SAXMachine
734
+ attribute :name
735
+ attribute :role
736
+ end
737
+ class ItemElement2
738
+ include SAXMachine
739
+ elements :author, :as => :authors, :class => AuthorElement2
740
+ end
741
+ @item = ItemElement2.parse(@xml)
742
+ end
743
+
744
+ it 'should have the child elements' do
745
+ @item.authors.should_not be_nil
746
+ @item.authors.count.should == 2
747
+ end
748
+
749
+ it 'should have the author names' do
750
+ @item.authors.first.name.should == 'John Doe'
751
+ @item.authors.last.name.should == 'Jane Doe'
752
+ end
753
+
754
+ it 'should have the author roles' do
755
+ @item.authors.first.role.should == 'writer'
756
+ @item.authors.last.role.should == 'artist'
757
+ end
758
+ end
759
+
760
+ describe "with mixed attributes and element values" do
761
+ before do
762
+ @xml = %[
763
+ <item id="1">
764
+ <author role="writer">John Doe</author>
765
+ </item>
766
+ ]
767
+ class AuthorElement3
768
+ include SAXMachine
769
+ value :name
770
+ attribute :role
771
+ end
772
+ class ItemElement3
773
+ include SAXMachine
774
+ element :author, :class => AuthorElement3
775
+ end
776
+ @item = ItemElement3.parse(@xml)
777
+ end
778
+
779
+ it 'should have the child elements' do
780
+ @item.author.should_not be_nil
781
+ end
782
+
783
+ it 'should have the author names' do
784
+ @item.author.name.should == 'John Doe'
785
+ end
786
+
787
+ it 'should have the author roles' do
788
+ @item.author.role.should == 'writer'
789
+ end
790
+ end
791
+
792
+ describe "with multiple mixed attributes and element values" do
793
+ before do
794
+ @xml = %[
795
+ <item id="1">
796
+ <title>sweet</title>
797
+ <author role="writer">John Doe</author>
798
+ <author role="artist">Jane Doe</author>
799
+ </item>
800
+ ]
801
+ class AuthorElement4
802
+ include SAXMachine
803
+ value :name
804
+ attribute :role
805
+ end
806
+ class ItemElement4
807
+ include SAXMachine
808
+ element :title
809
+ elements :author, :as => :authors, :class => AuthorElement4
810
+
811
+ def title=(blah)
812
+ #raise 'woo'
813
+ @title = blah
814
+ end
815
+ end
816
+ @item = ItemElement4.parse(@xml)
817
+ end
818
+
819
+ it 'should have the title' do
820
+ @item.title.should == 'sweet'
821
+ end
822
+
823
+ it 'should have the child elements' do
824
+ @item.authors.should_not be_nil
825
+ @item.authors.count.should == 2
826
+ end
827
+
828
+ it 'should have the author names' do
829
+ @item.authors.first.name.should == 'John Doe'
830
+ @item.authors.last.name.should == 'Jane Doe'
831
+ end
832
+
833
+ it 'should have the author roles' do
834
+ @item.authors.first.role.should == 'writer'
835
+ @item.authors.last.role.should == 'artist'
836
+ end
837
+ end
838
+ end