syndication 0.6 → 0.6.1
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.
- data/lib/syndication/common.rb +11 -5
- data/lib/syndication/feedburner.rb +18 -0
- data/rakefile +2 -2
- data/test/feedburntest.rb +79 -0
- data/test/rsstest.rb +102 -1
- metadata +5 -2
data/lib/syndication/common.rb
CHANGED
@@ -139,7 +139,8 @@ module Syndication
|
|
139
139
|
'http://purl.org/rss/1.0/modules/content/' => 'content',
|
140
140
|
'http://www.itunes.com/DTDs/Podcast-1.0.dtd' => 'itunes',
|
141
141
|
'http://www.w3.org/1999/xhtml' => 'xhtml',
|
142
|
-
'http://schemas.google.com/g/2005' => 'gd'
|
142
|
+
'http://schemas.google.com/g/2005' => 'gd',
|
143
|
+
'http://rssnamespace.org/feedburner/ext/1.0' => 'feedburner'
|
143
144
|
}
|
144
145
|
|
145
146
|
# Create a new AbstractParser. The optional argument consists of text to
|
@@ -272,11 +273,16 @@ module Syndication
|
|
272
273
|
|
273
274
|
# Supposed to be called when REXML finds a CDATA-encoded piece of text.
|
274
275
|
def cdata(s)
|
275
|
-
#
|
276
|
-
# encoded and decoded results to the user, and
|
277
|
-
# seem to pass CDATA via this callback method.
|
276
|
+
# For content_encoded we re-encode, because (a) the API for RSS content
|
277
|
+
# module provides both encoded and decoded results to the user, and
|
278
|
+
# (b) REXML doesn't always seem to pass CDATA via this callback method.
|
279
|
+
# For other elements, we keep the text decoded.
|
278
280
|
if @textstack.last
|
279
|
-
@
|
281
|
+
if @tagstack.last == 'content:encoded'
|
282
|
+
@textstack.last << "<![CDATA[#{s}]]>"
|
283
|
+
else
|
284
|
+
@textstack.last << s
|
285
|
+
end
|
280
286
|
end
|
281
287
|
end
|
282
288
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module Syndication
|
3
|
+
|
4
|
+
module Feedburner
|
5
|
+
module Item
|
6
|
+
# The original URL, before feedburner rewrote it for tracking purposes
|
7
|
+
attr_accessor :feedburner_origlink
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module RSS
|
13
|
+
class Item
|
14
|
+
include Feedburner::Item
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
|
|
5
5
|
require 'rake/testtask'
|
6
6
|
require 'rubygems'
|
7
7
|
|
8
|
-
PKG_VERSION = "0.6"
|
8
|
+
PKG_VERSION = "0.6.1"
|
9
9
|
|
10
10
|
desc "Create HTML documentation from RDOC"
|
11
11
|
Rake::RDocTask.new do |rd|
|
@@ -36,7 +36,7 @@ spec = Gem::Specification.new do |s|
|
|
36
36
|
end
|
37
37
|
s.require_path = "lib"
|
38
38
|
s.test_files = ["test/atomtest.rb", "test/rsstest.rb", "test/google.rb",
|
39
|
-
"test/tagsouptest.rb"]
|
39
|
+
"test/tagsouptest.rb", "test/feedburntest.rb"]
|
40
40
|
s.has_rdoc = true
|
41
41
|
s.extra_rdoc_files = ["README", "IMPLEMENTATION", "CHANGES", "DEVELOPER"]
|
42
42
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright � mathew <meta@pobox.com> 2006.
|
2
|
+
# Licensed under the same terms as Ruby.
|
3
|
+
|
4
|
+
require 'syndication/rss'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'syndication/dublincore'
|
7
|
+
require 'syndication/content'
|
8
|
+
require 'syndication/podcast'
|
9
|
+
require 'syndication/feedburner'
|
10
|
+
|
11
|
+
module Syndication
|
12
|
+
|
13
|
+
# This class contains the unit tests for the Syndication module.
|
14
|
+
class Tests < Test::Unit::TestCase
|
15
|
+
|
16
|
+
# A set of minimal assertions that can be applied to every well-formed parsed
|
17
|
+
# feed.
|
18
|
+
def baseline_rss_assertions(feed)
|
19
|
+
assert_not_nil(feed)
|
20
|
+
assert_kind_of(Syndication::RSS::Feed, feed)
|
21
|
+
loi = feed.items
|
22
|
+
assert_not_nil(loi)
|
23
|
+
assert_kind_of(Array, loi)
|
24
|
+
assert(loi.length >= 1)
|
25
|
+
assert_not_nil(loi[0])
|
26
|
+
assert_not_nil(loi[0].description)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_feedburner
|
30
|
+
xml = <<-EOF
|
31
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
32
|
+
<?xml-stylesheet href="http://feeds.sfgate.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?>
|
33
|
+
<?xml-stylesheet href="http://feeds.sfgate.com/~d/styles/itemcontent.css" type="text/css" media="screen"?>
|
34
|
+
<rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
|
35
|
+
<channel>
|
36
|
+
<title>SFGate: Top News Stories</title>
|
37
|
+
<link>http://www.sfgate.com/</link>
|
38
|
+
<description>Top news stories. From SFGate.com: the Bay Area's home page, online home of the San Francisco Chronicle and much more.</description>
|
39
|
+
<language>en-us</language>
|
40
|
+
<copyright>Copyright 2006 Hearst Communications, Inc.</copyright>
|
41
|
+
<managingEditor>ed@sfgate.com (SFGate Editorial staff)</managingEditor>
|
42
|
+
<webMaster>support@sfgate.com (SFGate technical support)</webMaster>
|
43
|
+
<lastBuildDate>Sun, 09 Jul 2006 14:21:10 PDT</lastBuildDate>
|
44
|
+
<category>News</category>
|
45
|
+
<category>Newspapers</category>
|
46
|
+
<category>San Francisco</category>
|
47
|
+
<category>San Francisco Bay Area</category>
|
48
|
+
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
|
49
|
+
<image>
|
50
|
+
<url>http://www.sfgate.com/templates/types/syndication/pages/rss/graphics/sfgate_logo.png</url>
|
51
|
+
<title>SFGate: Top News Stories</title>
|
52
|
+
<link>http://www.sfgate.com/</link>
|
53
|
+
</image>
|
54
|
+
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://www.sfgate.com/rss/feeds/news.xml" type="application/rss+xml" /><feedburner:browserFriendly>This is an RSS feed, but with the headlines made visible. Choose one of the buttons to add this feed to your favorite RSS reader.</feedburner:browserFriendly>
|
55
|
+
<item>
|
56
|
+
<title><![CDATA[Italy Beats France for 4th World Cup Title]]></title>
|
57
|
+
<link>http://feeds.sfgate.com/sfgate/rss/feeds/news?m=4300</link>
|
58
|
+
<description>Italy let France do nearly anything it wanted Sunday, except win the World Cup. That belongs to the Azzurri, 5-3 in a shootout after a 1-1 draw. Outplayed for an hour and into extra time, the Italians won it after French captain Zinedine Zidane was...<img src="http://feeds.sfgate.com/sfgate/rss/feeds/news?g=4300"/></description>
|
59
|
+
<author><![CDATA[By BARRY WILNER, AP Sports Writer]]></author>
|
60
|
+
<pubDate>Sun, 09 Jul 2006 14:14:59 PDT</pubDate>
|
61
|
+
|
62
|
+
<guid isPermaLink="false">/n/a/2006/07/09/sports/s134544D82.DTL</guid>
|
63
|
+
<feedburner:origLink>http://www.sfgate.com/cgi-bin/article.cgi?f=/n/a/2006/07/09/sports/s134544D82.DTL&feed=rss.news</feedburner:origLink>
|
64
|
+
</item>
|
65
|
+
</channel>
|
66
|
+
</rss>
|
67
|
+
EOF
|
68
|
+
f = Syndication::RSS::Parser.new.parse(xml)
|
69
|
+
il = f.items
|
70
|
+
assert_not_nil(il)
|
71
|
+
assert(il.length == 1)
|
72
|
+
i = il.first
|
73
|
+
assert_not_nil(i.feedburner_origlink)
|
74
|
+
assert(i.feedburner_origlink == "http://www.sfgate.com/cgi-bin/article.cgi?f=/n/a/2006/07/09/sports/s134544D82.DTL&feed=rss.news")
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/test/rsstest.rb
CHANGED
@@ -117,7 +117,6 @@ class Tests < Test::Unit::TestCase
|
|
117
117
|
<link>http://www.example.com</link>
|
118
118
|
<width>42</width>
|
119
119
|
<height>23</height>
|
120
|
-
<description>The Example Logo</description>
|
121
120
|
</image>
|
122
121
|
<rating>(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))</rating>
|
123
122
|
<textInput>
|
@@ -316,6 +315,108 @@ class Tests < Test::Unit::TestCase
|
|
316
315
|
assert(i.itunes_duration == 232, "Duration computed incorrectly")
|
317
316
|
end
|
318
317
|
|
318
|
+
# Test a well-formed RSS2 feed with every element possible and more than
|
319
|
+
# one item, with all kinds of stuff CDATA escaped.
|
320
|
+
def test_rss2_wf_full_cdata
|
321
|
+
xml = <<-EOF
|
322
|
+
<rss version="2">
|
323
|
+
<channel>
|
324
|
+
<title><![CDATA[Example Feed]]></title>
|
325
|
+
<link>http://www.example.com/</link>
|
326
|
+
<description><![CDATA[This is merely an example.]]></description>
|
327
|
+
<language>en-us</language>
|
328
|
+
<copyright>Copyright 2004 The Example Corporation.</copyright>
|
329
|
+
<managingEditor>editor@example.com</managingEditor>
|
330
|
+
<webMaster>webmaster@example.com</webMaster>
|
331
|
+
<pubDate>Sat, 07 Sep 2002 00:01:02 EDT</pubDate>
|
332
|
+
<lastBuildDate>Sat, 7 Sep 02 13:14:15 -0600</lastBuildDate>
|
333
|
+
<category>examples</category>
|
334
|
+
<category>boring</category>
|
335
|
+
<generator>vim of course</generator>
|
336
|
+
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
|
337
|
+
<cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="pingMe" protocol="soap"/>
|
338
|
+
<ttl>90</ttl>
|
339
|
+
<image>
|
340
|
+
<title><![CDATA[Example Inc]]></title>
|
341
|
+
<url>http://www.example.com/images/logo.jpg</url>
|
342
|
+
<link>http://www.example.com</link>
|
343
|
+
<width>42</width>
|
344
|
+
<height>23</height>
|
345
|
+
</image>
|
346
|
+
<rating>(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))</rating>
|
347
|
+
<textInput>
|
348
|
+
<title>Submit</title>
|
349
|
+
<description>Enter keywords</description>
|
350
|
+
<name>SearchKeywords</name>
|
351
|
+
<link>http://www.example.com/cgi-bin/search.pl</link>
|
352
|
+
</textInput>
|
353
|
+
<skipHours>
|
354
|
+
<hour>0</hour>
|
355
|
+
<hour>23</hour>
|
356
|
+
</skipHours>
|
357
|
+
<skipDays>
|
358
|
+
<day>Monday</day>
|
359
|
+
<day>Sunday</day>
|
360
|
+
</skipDays>
|
361
|
+
<item>
|
362
|
+
<title>Our stock price shot up</title>
|
363
|
+
<link>http://www.example.com/news/2.html</link>
|
364
|
+
<description>We were hyped in the press!</description>
|
365
|
+
</item>
|
366
|
+
<item>
|
367
|
+
<title><![CDATA[Unencoded < > and & are allowed.]]></title>
|
368
|
+
<link><![CDATA[http://www.example.com/news/1.html]]></link>
|
369
|
+
<description><![CDATA[If this was any less interesting, it would be amazing.]]></description>
|
370
|
+
<author><![CDATA[fred@example.com]]></author>
|
371
|
+
<pubDate>Sat, 07 Sep 2002 00:01:02 EDT</pubDate>
|
372
|
+
<category>dull</category>
|
373
|
+
<category>amazingly</category>
|
374
|
+
<comments>http://www.example.com/news/comments/1.html</comments>
|
375
|
+
<enclosure url="http://www.example.com/mp3/advertisement.mp3" length="123987" type="audio/mpeg" />
|
376
|
+
<guid>4asd98dgf9a74@example.com</guid>
|
377
|
+
<source url="http://www.example.com/news.xml">Example News</source>
|
378
|
+
</item>
|
379
|
+
</channel>
|
380
|
+
</rss>
|
381
|
+
EOF
|
382
|
+
f = Syndication::RSS::Parser.new.parse(xml)
|
383
|
+
baseline_rss_assertions(f)
|
384
|
+
for elem in %w(title link description language copyright managingeditor webmaster pubdate lastbuilddate category generator docs cloud ttl textinput rating skiphours skipdays)
|
385
|
+
assert_not_nil(f.channel.send(elem), "feed.channel.#{elem} is nil, it shouldn't be")
|
386
|
+
assert(f.channel.send(elem).to_s.length > 0)
|
387
|
+
end
|
388
|
+
# Check CDATA is decoded properly
|
389
|
+
assert(f.channel.title == 'Example Feed')
|
390
|
+
assert(f.channel.description == 'This is merely an example.')
|
391
|
+
items = f.items
|
392
|
+
assert(items.length == 2)
|
393
|
+
i = items.last
|
394
|
+
for elem in %w(title link description author pubdate category comments enclosure guid source)
|
395
|
+
assert_not_nil(i.send(elem), "feed.channel.item[1].#{elem} is nil, it shouldn't be")
|
396
|
+
end
|
397
|
+
cats = i.category
|
398
|
+
assert(i.title == 'Unencoded < > and & are allowed.')
|
399
|
+
assert(i.link == 'http://www.example.com/news/1.html')
|
400
|
+
assert(cats.length == 2)
|
401
|
+
assert(cats.first == 'dull')
|
402
|
+
assert(cats.last == 'amazingly')
|
403
|
+
assert(f.channel.skiphours.length == 2)
|
404
|
+
assert(f.channel.skiphours.first == 0)
|
405
|
+
assert(f.channel.skiphours.last == 23)
|
406
|
+
assert(f.channel.pubdate.kind_of?(DateTime))
|
407
|
+
assert(f.channel.lastbuilddate.kind_of?(DateTime))
|
408
|
+
assert(f.channel.pubdate.mday == 7)
|
409
|
+
assert(f.channel.pubdate.month == 9)
|
410
|
+
assert(f.channel.lastbuilddate.mday == 7)
|
411
|
+
assert(f.channel.lastbuilddate.month == 9)
|
412
|
+
c = f.channel
|
413
|
+
assert_not_nil(c)
|
414
|
+
assert_kind_of(Syndication::RSS::Channel, c)
|
415
|
+
assert_not_nil(c.title)
|
416
|
+
assert_not_nil(c.link)
|
417
|
+
assert_not_nil(c.description)
|
418
|
+
end
|
419
|
+
|
319
420
|
end
|
320
421
|
|
321
422
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: syndication
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version:
|
7
|
-
date: 2006-
|
6
|
+
version: 0.6.1
|
7
|
+
date: 2006-07-17 00:00:00 -05:00
|
8
8
|
summary: A web syndication parser for Atom and RSS with a uniform API
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -38,6 +38,8 @@ files:
|
|
38
38
|
- lib/syndication/rss.rb
|
39
39
|
- lib/syndication/syndication.rb
|
40
40
|
- lib/syndication/atom.rb
|
41
|
+
- lib/syndication/feedburner.rb
|
42
|
+
- test/feedburntest.rb
|
41
43
|
- test/tagsouptest.rb
|
42
44
|
- test/google.rb
|
43
45
|
- test/rsstest.rb
|
@@ -55,6 +57,7 @@ test_files:
|
|
55
57
|
- test/rsstest.rb
|
56
58
|
- test/google.rb
|
57
59
|
- test/tagsouptest.rb
|
60
|
+
- test/feedburntest.rb
|
58
61
|
rdoc_options: []
|
59
62
|
|
60
63
|
extra_rdoc_files:
|