simple-rss 1.0.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.
- data/LICENSE +429 -0
- data/README +40 -0
- data/Rakefile +90 -0
- data/doc/classes/SimpleRSS.html +279 -0
- data/doc/classes/SimpleRSS.src/M000001.html +21 -0
- data/doc/classes/SimpleRSS.src/M000002.html +16 -0
- data/doc/classes/SimpleRSS.src/M000004.html +18 -0
- data/doc/classes/SimpleRSS.src/M000005.html +18 -0
- data/doc/classes/SimpleRSS.src/M000006.html +18 -0
- data/doc/classes/SimpleRSS.src/M000007.html +18 -0
- data/doc/classes/SimpleRSS.src/M000008.html +18 -0
- data/doc/classes/SimpleRSSError.html +111 -0
- data/doc/created.rid +1 -0
- data/doc/files/README.html +170 -0
- data/doc/files/lib/simple-rss_rb.html +109 -0
- data/doc/fr_class_index.html +28 -0
- data/doc/fr_file_index.html +28 -0
- data/doc/fr_method_index.html +34 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/simple-rss.rb +127 -0
- data/test/base/base_test.rb +48 -0
- data/test/data/atom.xml +45 -0
- data/test/data/not-rss.xml +8 -0
- data/test/data/rss09.rdf +76 -0
- data/test/data/rss20.xml +818 -0
- data/test/test_helper.rb +4 -0
- metadata +73 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Classes
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Classes</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Classes</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="classes/SimpleRSS.html">SimpleRSS</a><br />
|
24
|
+
<a href="classes/SimpleRSSError.html">SimpleRSSError</a><br />
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</body>
|
28
|
+
</html>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Files
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Files</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Files</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="files/README.html">README</a><br />
|
24
|
+
<a href="files/lib/simple-rss_rb.html">lib/simple-rss.rb</a><br />
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</body>
|
28
|
+
</html>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Methods
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Methods</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Methods</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="classes/SimpleRSS.html#M000002">channel (SimpleRSS)</a><br />
|
24
|
+
<a href="classes/SimpleRSS.html#M000003">feed (SimpleRSS)</a><br />
|
25
|
+
<a href="classes/SimpleRSS.html#M000004">feed_tags (SimpleRSS)</a><br />
|
26
|
+
<a href="classes/SimpleRSS.html#M000005">feed_tags= (SimpleRSS)</a><br />
|
27
|
+
<a href="classes/SimpleRSS.html#M000006">item_tags (SimpleRSS)</a><br />
|
28
|
+
<a href="classes/SimpleRSS.html#M000007">item_tags= (SimpleRSS)</a><br />
|
29
|
+
<a href="classes/SimpleRSS.html#M000001">new (SimpleRSS)</a><br />
|
30
|
+
<a href="classes/SimpleRSS.html#M000008">parse (SimpleRSS)</a><br />
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</body>
|
34
|
+
</html>
|
data/doc/index.html
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
5
|
+
|
6
|
+
<!--
|
7
|
+
|
8
|
+
Simple RSS - A Flexible RSS and Atom reader for Ruby
|
9
|
+
|
10
|
+
-->
|
11
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
12
|
+
<head>
|
13
|
+
<title>Simple RSS - A Flexible RSS and Atom reader for Ruby</title>
|
14
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
15
|
+
</head>
|
16
|
+
<frameset rows="20%, 80%">
|
17
|
+
<frameset cols="25%,35%,45%">
|
18
|
+
<frame src="fr_file_index.html" title="Files" name="Files" />
|
19
|
+
<frame src="fr_class_index.html" name="Classes" />
|
20
|
+
<frame src="fr_method_index.html" name="Methods" />
|
21
|
+
</frameset>
|
22
|
+
<frame src="files/README.html" name="docwin" />
|
23
|
+
</frameset>
|
24
|
+
</html>
|
data/doc/rdoc-style.css
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
data/lib/simple-rss.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
class SimpleRSS
|
5
|
+
attr_reader :items, :source
|
6
|
+
alias :entries :items
|
7
|
+
|
8
|
+
@@feed_tags = [
|
9
|
+
:id,
|
10
|
+
:title, :subtitle, :link,
|
11
|
+
:description,
|
12
|
+
:author, :webMaster, :managingEditor, :contributor,
|
13
|
+
:pubDate, :lastBuildDate, :updated,
|
14
|
+
:generator, :language, :docs, :cloud,
|
15
|
+
:ttl, :skipHours, :skipDays,
|
16
|
+
:image, :logo, :icon, :rating,
|
17
|
+
:rights, :copyright,
|
18
|
+
:textInput
|
19
|
+
]
|
20
|
+
|
21
|
+
@@item_tags = [
|
22
|
+
:id,
|
23
|
+
:title, :link,
|
24
|
+
:author, :contributor,
|
25
|
+
:description, :summary, :content, :'content:encoded', :comments,
|
26
|
+
:pubDate, :published, :updated, :expirationDate,
|
27
|
+
:category, :guid,
|
28
|
+
:'trackback:ping', :'trackback:about',
|
29
|
+
:'dc:creator', :'dc:title', :'dc:subject', :'dc:rights', :'dc:publisher'
|
30
|
+
]
|
31
|
+
|
32
|
+
def initialize(source)
|
33
|
+
@source = source.respond_to?(:read) ? source.read : source.to_s
|
34
|
+
@items = Array.new
|
35
|
+
|
36
|
+
parse
|
37
|
+
end
|
38
|
+
|
39
|
+
def channel() self end
|
40
|
+
alias :feed :channel
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def feed_tags
|
44
|
+
@@feed_tags
|
45
|
+
end
|
46
|
+
def feed_tags=(ft)
|
47
|
+
@@feed_tags = ft
|
48
|
+
end
|
49
|
+
|
50
|
+
def item_tags
|
51
|
+
@@item_tags
|
52
|
+
end
|
53
|
+
def item_tags=(it)
|
54
|
+
@@item_tags = it
|
55
|
+
end
|
56
|
+
|
57
|
+
# The strict attribute is for compatibility with Ruby's standard RSS parser
|
58
|
+
def parse(source, strict=false)
|
59
|
+
new source
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def parse
|
66
|
+
raise SimpleRSSError, "Poorly formatted feed" unless @source =~ %r{<(channel|feed).*?>.*?</(channel|feed)>}mi
|
67
|
+
|
68
|
+
# Feed's title and link
|
69
|
+
feed_content = $1 if @source =~ %r{(.*?)<(rss:|atom:)?(item|entry).*?>.*?</(rss:|atom:)?(item|entry)>}mi
|
70
|
+
|
71
|
+
@@feed_tags.each do |tag|
|
72
|
+
if feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
|
73
|
+
nil
|
74
|
+
elsif feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
|
75
|
+
nil
|
76
|
+
elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
|
77
|
+
nil
|
78
|
+
elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
if $2 || $3
|
83
|
+
eval %{ @#{ clean_tag tag } = clean_content(tag, $2, $3) }
|
84
|
+
self.class.class_eval %{ attr_reader tag }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# RSS items' title, link, and description
|
89
|
+
@source.scan( %r{<(rss:|atom:)?(item|entry).*?>(.*?)</(rss:|atom:)?(item|entry)>}mi ) do |match|
|
90
|
+
item = Hash.new
|
91
|
+
@@item_tags.each do |tag|
|
92
|
+
if match[2] =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
|
93
|
+
nil
|
94
|
+
elsif match[2] =~ %r{<(rss:|atom:)?#{tag}(.*?)/\s*>}mi
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
item[clean_tag(tag)] = clean_content(tag, $2, $3) if $2 || $3
|
98
|
+
end
|
99
|
+
def item.method_missing(name, *args) self[name] end
|
100
|
+
@items << item
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
def clean_content(tag, attrs, content)
|
106
|
+
content = content.to_s
|
107
|
+
case tag
|
108
|
+
when :pubDate, :lastBuildDate, :published, :updated, :expirationDate
|
109
|
+
Time.parse(content)
|
110
|
+
when :author, :contributor, :skipHours, :skipDays
|
111
|
+
unescape(content.gsub(/<.*?>/,''))
|
112
|
+
else
|
113
|
+
content.empty? && "#{attrs} " =~ /href=['"]?([^'"]*)['" ]/mi ? $1.strip : unescape(content)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def clean_tag(tag)
|
118
|
+
tag.to_s.gsub(':','_').intern
|
119
|
+
end
|
120
|
+
|
121
|
+
def unescape(content)
|
122
|
+
CGI.unescape(content).gsub(/(<!\[CDATA\[|\]\]>)/,'').strip
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class SimpleRSSError < StandardError
|
127
|
+
end
|