simple-rss 1.3.3 → 2.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/lib/simple-rss.rb CHANGED
@@ -1,160 +1,279 @@
1
- require 'cgi'
2
- require 'time'
1
+ # rbs_inline: enabled
2
+
3
+ require "cgi"
4
+ require "time"
3
5
 
4
6
  class SimpleRSS
5
- VERSION = "1.3.3"
6
-
7
- attr_reader :items, :source
8
- alias :entries :items
9
-
10
- @@feed_tags = [
11
- :id,
12
- :title, :subtitle, :link,
13
- :description,
14
- :author, :webMaster, :managingEditor, :contributor,
15
- :pubDate, :lastBuildDate, :updated, :'dc:date',
16
- :generator, :language, :docs, :cloud,
17
- :ttl, :skipHours, :skipDays,
18
- :image, :logo, :icon, :rating,
19
- :rights, :copyright,
20
- :textInput, :'feedburner:browserFriendly',
21
- :'itunes:author', :'itunes:category'
22
- ]
23
-
24
- @@item_tags = [
25
- :id,
26
- :title, :link, :'link+alternate', :'link+self', :'link+edit', :'link+replies',
27
- :author, :contributor,
28
- :description, :summary, :content, :'content:encoded', :comments,
29
- :pubDate, :published, :updated, :expirationDate, :modified, :'dc:date',
30
- :category, :guid,
31
- :'trackback:ping', :'trackback:about',
32
- :'dc:creator', :'dc:title', :'dc:subject', :'dc:rights', :'dc:publisher',
33
- :'feedburner:origLink',
34
- :'media:content#url', :'media:content#type', :'media:content#height', :'media:content#width', :'media:content#duration',
35
- :'media:title', :'media:thumbnail#url', :'media:thumbnail#height', :'media:thumbnail#width',
36
- :'media:credit', :'media:credit#role',
37
- :'media:category', :'media:category#scheme'
38
- ]
39
-
40
- def initialize(source, options={})
41
- @source = source.respond_to?(:read) ? source.read : source.to_s
42
- @items = Array.new
43
- @options = Hash.new.update(options)
44
-
45
- parse
46
- end
47
-
48
- def channel() self end
49
- alias :feed :channel
50
-
51
- class << self
52
- def feed_tags
53
- @@feed_tags
54
- end
55
- def feed_tags=(ft)
56
- @@feed_tags = ft
57
- end
58
-
59
- def item_tags
60
- @@item_tags
61
- end
62
- def item_tags=(it)
63
- @@item_tags = it
64
- end
65
-
66
- # The strict attribute is for compatibility with Ruby's standard RSS parser
67
- def parse(source, options={})
68
- new source, options
69
- end
70
- end
71
-
72
- private
73
-
74
- def parse
75
- raise SimpleRSSError, "Poorly formatted feed" unless @source =~ %r{<(channel|feed).*?>.*?</(channel|feed)>}mi
76
-
77
- # Feed's title and link
78
- feed_content = $1 if @source =~ %r{(.*?)<(rss:|atom:)?(item|entry).*?>.*?</(rss:|atom:)?(item|entry)>}mi
79
-
80
- @@feed_tags.each do |tag|
81
- if feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
82
- nil
83
- elsif feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
84
- nil
85
- elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
86
- nil
87
- elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
88
- nil
89
- end
90
-
91
- if $2 || $3
92
- tag_cleaned = clean_tag(tag)
93
- instance_variable_set("@#{ tag_cleaned }", clean_content(tag, $2, $3))
94
- self.class.class_eval("attr_reader :#{ tag_cleaned }")
95
- end
96
- end
97
-
98
- # RSS items' title, link, and description
99
- @source.scan( %r{<(rss:|atom:)?(item|entry)([\s][^>]*)?>(.*?)</(rss:|atom:)?(item|entry)>}mi ) do |match|
100
- item = Hash.new
101
- @@item_tags.each do |tag|
102
- if tag.to_s.include?("+")
103
- tag_data = tag.to_s.split("+")
104
- tag = tag_data[0]
105
- rel = tag_data[1]
106
- if match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)rel=['"]#{rel}['"](.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
107
- nil
108
- elsif match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)rel=['"]#{rel}['"](.*?)/\s*>}mi
109
- nil
110
- end
111
- item[clean_tag("#{tag}+#{rel}")] = clean_content(tag, $3, $4) if $3 || $4
112
- elsif tag.to_s.include?("#")
113
- tag_data = tag.to_s.split("#")
114
- tag = tag_data[0]
115
- attrib = tag_data[1]
116
- if match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)#{attrib}=['"](.*?)['"](.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
117
- nil
118
- elsif match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)#{attrib}=['"](.*?)['"](.*?)/\s*>}mi
119
- nil
120
- end
121
- item[clean_tag("#{tag}_#{attrib}")] = clean_content(tag, attrib, $3) if $3
122
- else
123
- if match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
124
- nil
125
- elsif match[3] =~ %r{<(rss:|atom:)?#{tag}(.*?)/\s*>}mi
126
- nil
127
- end
128
- item[clean_tag(tag)] = clean_content(tag, $2, $3) if $2 || $3
129
- end
130
- end
131
- def item.method_missing(name, *args) self[name] end
132
- @items << item
133
- end
134
- end
135
-
136
- def clean_content(tag, attrs, content)
137
- content = content.to_s
138
- case tag
139
- when :pubDate, :lastBuildDate, :published, :updated, :expirationDate, :modified, :'dc:date'
140
- Time.parse(content) rescue unescape(content)
141
- when :author, :contributor, :skipHours, :skipDays
142
- unescape(content.gsub(/<.*?>/,''))
143
- else
144
- content.empty? && "#{attrs} " =~ /href=['"]?([^'"]*)['" ]/mi ? $1.strip : unescape(content)
145
- end
146
- end
147
-
148
- def clean_tag(tag)
149
- tag.to_s.gsub(':','_').intern
150
- end
151
-
7
+ VERSION = "2.0.0".freeze
8
+
9
+ # @rbs @items: Array[Hash[Symbol, untyped]]
10
+ # @rbs @source: String
11
+ # @rbs @options: Hash[Symbol, untyped]
12
+
13
+ attr_reader :items #: Array[Hash[Symbol, untyped]]
14
+ attr_reader :source #: String
15
+ alias entries items #: Array[Hash[Symbol, untyped]]
16
+
17
+ @@feed_tags = %i[
18
+ id
19
+ title subtitle link
20
+ description
21
+ author webMaster managingEditor contributor
22
+ pubDate lastBuildDate updated dc:date
23
+ generator language docs cloud
24
+ ttl skipHours skipDays
25
+ image logo icon rating
26
+ rights copyright
27
+ textInput feedburner:browserFriendly
28
+ itunes:author itunes:category
29
+ ]
30
+
31
+ @@item_tags = %i[
32
+ id
33
+ title link link+alternate link+self link+edit link+replies
34
+ author contributor
35
+ description summary content content:encoded comments
36
+ pubDate published updated expirationDate modified dc:date
37
+ category guid
38
+ trackback:ping trackback:about
39
+ dc:creator dc:title dc:subject dc:rights dc:publisher
40
+ feedburner:origLink
41
+ media:content#url media:content#type media:content#height media:content#width media:content#duration
42
+ media:title media:thumbnail#url media:thumbnail#height media:thumbnail#width
43
+ media:credit media:credit#role
44
+ media:category media:category#scheme
45
+ ]
46
+
47
+ # @rbs (untyped, ?Hash[Symbol, untyped]) -> void
48
+ def initialize(source, options = {})
49
+ @source = source.respond_to?(:read) ? source.read.to_s : source.to_s
50
+ @items = [] #: Array[Hash[Symbol, untyped]]
51
+ @options = {} #: Hash[Symbol, untyped]
52
+ @options.update(options)
53
+
54
+ parse
55
+ end
56
+
57
+ # @rbs () -> SimpleRSS
58
+ def channel
59
+ self
60
+ end
61
+ alias feed channel
62
+
63
+ class << self
64
+ # @rbs () -> Array[Symbol]
65
+ def feed_tags
66
+ @@feed_tags
67
+ end
68
+
69
+ # @rbs (Array[Symbol]) -> Array[Symbol]
70
+ def feed_tags=(ft)
71
+ @@feed_tags = ft
72
+ end
73
+
74
+ # @rbs () -> Array[Symbol]
75
+ def item_tags
76
+ @@item_tags
77
+ end
78
+
79
+ # @rbs (Array[Symbol]) -> Array[Symbol]
80
+ def item_tags=(it)
81
+ @@item_tags = it
82
+ end
83
+
84
+ # The strict attribute is for compatibility with Ruby's standard RSS parser
85
+ #
86
+ # @rbs (untyped, ?Hash[Symbol, untyped]) -> SimpleRSS
87
+ def parse(source, options = {})
88
+ new source, options
89
+ end
90
+ end
91
+
92
+ DATE_TAGS = %i[pubDate lastBuildDate published updated expirationDate modified dc:date].freeze
93
+ STRIP_HTML_TAGS = %i[author contributor skipHours skipDays].freeze
94
+
95
+ private
96
+
97
+ # @rbs () -> void
98
+ def parse
99
+ raise SimpleRSSError, "Poorly formatted feed" unless @source =~ %r{<(channel|feed).*?>.*?</(channel|feed)>}mi
100
+
101
+ # Feed's title and link
102
+ feed_content = Regexp.last_match(1) if @source =~ %r{(.*?)<(rss:|atom:)?(item|entry).*?>.*?</(rss:|atom:)?(item|entry)>}mi
103
+
104
+ # Capture channel/feed tag attributes
105
+ feed_attrs = nil
106
+ if @source =~ /<(channel|feed)([\s][^>]*)?>/mi
107
+ feed_attrs = Regexp.last_match(2)
108
+ end
109
+
110
+ @@feed_tags.each do |tag|
111
+ next if tag.to_s.strip.empty?
112
+
113
+ tag_str = tag.to_s
114
+
115
+ # Handle channel#attr or feed#attr syntax
116
+ if tag_str.include?("#")
117
+ parse_feed_attr_tag(tag_str, feed_attrs)
118
+ next
119
+ end
120
+
121
+ if feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
122
+ nil
123
+ elsif feed_content && feed_content =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
124
+ nil
125
+ elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi
126
+ nil
127
+ elsif @source =~ %r{<(rss:|atom:)?#{tag}(.*?)\/\s*>}mi
128
+ nil
129
+ end
130
+
131
+ next unless Regexp.last_match(2) || Regexp.last_match(3)
132
+
133
+ tag_cleaned = clean_tag(tag)
134
+ instance_variable_set("@#{tag_cleaned}", clean_content(tag, Regexp.last_match(2), Regexp.last_match(3)))
135
+ self.class.class_eval("attr_reader :#{tag_cleaned}")
136
+ end
137
+
138
+ # RSS items' title, link, and description
139
+ @source.scan(%r{<(rss:|atom:)?(item|entry)([\s][^>]*)?>(.*?)</(rss:|atom:)?(item|entry)>}mi) do |match|
140
+ item = {} #: Hash[Symbol, untyped]
141
+ @@item_tags.each do |tag|
142
+ next if tag.to_s.strip.empty?
143
+
144
+ parse_item_tag(item, tag, match[3], match[2])
145
+ end
146
+ item.define_singleton_method(:method_missing) { |name, *| self[name] }
147
+ @items << item
148
+ end
149
+ end
150
+
151
+ # @rbs (Hash[Symbol, untyped], Symbol, String?, String?) -> void
152
+ def parse_item_tag(item, tag, content, item_attrs = nil)
153
+ return if content.nil?
154
+
155
+ tag_str = tag.to_s
156
+
157
+ return parse_rel_tag(item, tag_str, content) if tag_str.include?("+")
158
+ return parse_attr_tag(item, tag_str, content, item_attrs) if tag_str.include?("#")
159
+
160
+ parse_simple_tag(item, tag, content)
161
+ end
162
+
163
+ # @rbs (Hash[Symbol, untyped], String, String) -> void
164
+ def parse_rel_tag(item, tag_str, content)
165
+ tag, rel = tag_str.split("+")
166
+ return unless tag && rel
167
+
168
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)rel=['"]#{rel}['"](.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi ||
169
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)rel=['"]#{rel}['"](.*?)/\s*>}mi
170
+
171
+ return unless Regexp.last_match(3) || Regexp.last_match(4)
172
+
173
+ item[clean_tag("#{tag}+#{rel}")] = clean_content(tag.to_sym, Regexp.last_match(3), Regexp.last_match(4))
174
+ end
175
+
176
+ # @rbs (String, String?) -> void
177
+ def parse_feed_attr_tag(tag_str, feed_attrs)
178
+ tag, attrib = tag_str.split("#")
179
+ return unless tag && attrib && feed_attrs
180
+
181
+ # Only handle channel or feed tags
182
+ return unless %w[channel feed].include?(tag)
183
+ return unless feed_attrs =~ /#{attrib}=['"](.*?)['"]/mi
184
+
185
+ tag_cleaned = clean_tag("#{tag}_#{attrib}")
186
+ instance_variable_set("@#{tag_cleaned}", clean_content(tag.to_sym, attrib, Regexp.last_match(1)))
187
+ self.class.class_eval("attr_reader :#{tag_cleaned}")
188
+ end
189
+
190
+ # @rbs (Hash[Symbol, untyped], String, String, String?) -> void
191
+ def parse_attr_tag(item, tag_str, content, item_attrs = nil)
192
+ tag, attrib = tag_str.split("#")
193
+ return unless tag && attrib
194
+
195
+ # Handle attributes on the item/entry tag itself
196
+ if %w[item entry].include?(tag) && item_attrs
197
+ return unless item_attrs =~ /#{attrib}=['"](.*?)['"]/mi
198
+
199
+ item[clean_tag("#{tag}_#{attrib}")] = clean_content(tag.to_sym, attrib, Regexp.last_match(1))
200
+ return
201
+ end
202
+
203
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)#{attrib}=['"](.*?)['"](.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi ||
204
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)#{attrib}=['"](.*?)['"](.*?)/\s*>}mi
205
+
206
+ return unless Regexp.last_match(3)
207
+
208
+ item[clean_tag("#{tag}_#{attrib}")] = clean_content(tag.to_sym, attrib, Regexp.last_match(3))
209
+ end
210
+
211
+ # @rbs (Hash[Symbol, untyped], Symbol, String) -> void
212
+ def parse_simple_tag(item, tag, content)
213
+ # Handle array_tags option - collect all values for this tag
214
+ if array_tag?(tag)
215
+ values = content.scan(%r{<(rss:|atom:)?#{tag}(?:[^>]*)>(.*?)</(rss:|atom:)?#{tag}>}mi).map do |match|
216
+ clean_content(tag, nil, match[1])
217
+ end
218
+ item[clean_tag(tag)] = values unless values.empty?
219
+ return
220
+ end
221
+
222
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)>(.*?)</(rss:|atom:)?#{tag}>}mi ||
223
+ content =~ %r{<(rss:|atom:)?#{tag}(.*?)/\s*>}mi
224
+
225
+ return unless Regexp.last_match(2) || Regexp.last_match(3)
226
+
227
+ item[clean_tag(tag)] = clean_content(tag, Regexp.last_match(2), Regexp.last_match(3))
228
+ end
229
+
230
+ # @rbs (Symbol) -> bool
231
+ def array_tag?(tag)
232
+ array_tags = @options[:array_tags]
233
+ return false unless array_tags.is_a?(Array)
234
+
235
+ array_tags.include?(tag) || array_tags.include?(tag.to_sym)
236
+ end
237
+
238
+ # @rbs (Symbol, String?, String?) -> (Time | String)
239
+ def clean_content(tag, attrs, content)
240
+ content = content.to_s
241
+
242
+ return parse_date(content) if DATE_TAGS.include?(tag)
243
+ return unescape(content.gsub(/<.*?>/, "")) if STRIP_HTML_TAGS.include?(tag)
244
+ return extract_href(attrs) if content.empty? && attrs
245
+
246
+ unescape(content)
247
+ end
248
+
249
+ # @rbs (String) -> (Time | String)
250
+ def parse_date(content)
251
+ Time.parse(content)
252
+ rescue StandardError
253
+ unescape(content)
254
+ end
255
+
256
+ # @rbs (String?) -> String
257
+ def extract_href(attrs)
258
+ return "" unless "#{attrs} " =~ /href=['"]?([^'"]*)['" ]/mi
259
+
260
+ Regexp.last_match(1)&.strip || ""
261
+ end
262
+
263
+ # @rbs (Symbol | String) -> Symbol
264
+ def clean_tag(tag)
265
+ tag.to_s.tr(":", "_").intern
266
+ end
267
+
268
+ # @rbs (String) -> String
152
269
  def unescape(content)
153
- if content =~ /([^-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]%)/ then
154
- CGI.unescape(content)
155
- else
156
- content
157
- end.gsub(/(<!\[CDATA\[|\]\]>)/,'').strip
270
+ result = if content =~ %r{([^-_.!~*'()a-zA-Z\d;/?:@&=+$,\[\]]%)}
271
+ CGI.unescape(content)
272
+ else
273
+ content
274
+ end.gsub(/(<!\[CDATA\[|\]\]>)/, "").strip
275
+
276
+ result.encode(Encoding::UTF_8)
158
277
  end
159
278
  end
160
279
 
data/simple-rss.gemspec CHANGED
@@ -1,15 +1,14 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "simple-rss"
3
- s.version = "1.3.3"
4
- s.version = "#{s.version}-alpha-#{ENV['TRAVIS_BUILD_NUMBER']}" if ENV['TRAVIS']
5
- s.date = "2015-08-17"
3
+ s.version = "2.0.0"
4
+ s.date = "2025-12-28"
6
5
  s.summary = "A simple, flexible, extensible, and liberal RSS and Atom reader for Ruby. It is designed to be backwards compatible with the standard RSS parser, but will never do RSS generation."
7
6
  s.email = "lucas@rufy.com"
8
7
  s.homepage = "http://github.com/cardmagic/simple-rss"
9
8
  s.description = "A simple, flexible, extensible, and liberal RSS and Atom reader for Ruby. It is designed to be backwards compatible with the standard RSS parser, but will never do RSS generation."
10
9
  s.authors = ["Lucas Carlson"]
11
- s.files = ["install.rb", "lib", "lib/simple-rss.rb", "LICENSE", "Rakefile", "README.markdown", "simple-rss.gemspec", "test", "test/base", "test/base/base_test.rb", "test/data", "test/data/atom.xml", "test/data/not-rss.xml", "test/data/rss09.rdf", "test/data/rss20.xml", "test/test_helper.rb"]
12
- s.rubyforge_project = 'simple-rss'
10
+ s.files = Dir["lib/**/*", "test/**/*", "LICENSE", "README.markdown", "Rakefile", "simple-rss.gemspec"]
11
+ s.rubyforge_project = "simple-rss"
13
12
  s.add_development_dependency "rake"
14
13
  s.add_development_dependency "rdoc"
15
14
  s.add_development_dependency "test-unit"
@@ -0,0 +1,37 @@
1
+ require "test_helper"
2
+
3
+ class ArrayTagsTest < Test::Unit::TestCase
4
+ def setup
5
+ @rss20 = SimpleRSS.parse(
6
+ open(File.dirname(__FILE__) + "/../data/rss20.xml"),
7
+ array_tags: [:category]
8
+ )
9
+ @rss20_no_array = SimpleRSS.parse(
10
+ open(File.dirname(__FILE__) + "/../data/rss20.xml")
11
+ )
12
+ end
13
+
14
+ def test_array_tag_returns_array
15
+ assert_kind_of Array, @rss20.items.first.category
16
+ end
17
+
18
+ def test_array_tag_contains_all_values
19
+ categories = @rss20.items.first.category
20
+ assert_equal 2, categories.size
21
+ assert_includes categories, "Programming"
22
+ assert_includes categories, "Ruby"
23
+ end
24
+
25
+ def test_single_value_still_returns_array
26
+ # Item with only one category should still return an array
27
+ categories = @rss20.items[2].category
28
+ assert_kind_of Array, categories
29
+ assert_equal 1, categories.size
30
+ assert_equal ["General"], categories
31
+ end
32
+
33
+ def test_without_array_tags_returns_string
34
+ # Default behavior should return just the first/last match as a string
35
+ assert_kind_of String, @rss20_no_array.items.first.category
36
+ end
37
+ end
@@ -1,83 +1,82 @@
1
- # -*- coding: utf-8 -*-
2
- require 'test_helper'
1
+ require "test_helper"
3
2
  class BaseTest < Test::Unit::TestCase
4
- def setup
5
- @rss09 = SimpleRSS.parse open(File.dirname(__FILE__) + '/../data/rss09.rdf')
6
- @rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + '/../data/rss20.xml')
7
- @rss20_utf8 = SimpleRSS.parse open(File.dirname(__FILE__) + '/../data/rss20_utf8.xml')
8
- @media_rss = SimpleRSS.parse open(File.dirname(__FILE__) + '/../data/media_rss.xml')
9
- @atom = SimpleRSS.parse open(File.dirname(__FILE__) + '/../data/atom.xml')
10
- end
11
-
12
- def test_channel
13
- assert_equal @rss09, @rss09.channel
14
- assert_equal @rss20, @rss20.channel
15
- assert_equal @atom, @atom.feed
16
- end
17
-
18
- def test_items
19
- assert_kind_of Array, @rss09.items
20
- assert_kind_of Array, @rss20.items
21
- assert_kind_of Array, @atom.entries
22
- end
23
-
24
- def test_rss09
25
- assert_equal 10, @rss09.items.size
26
- assert_equal "Slashdot", @rss09.title
27
- assert_equal "http://slashdot.org/", @rss09.channel.link
28
- assert_equal "http://books.slashdot.org/article.pl?sid=05/08/29/1319236&amp;from=rss", @rss09.items.first.link
29
- assert_equal "http://books.slashdot.org/article.pl?sid=05/08/29/1319236&amp;from=rss", @rss09.items.first[:link]
3
+ def setup
4
+ @rss09 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss09.rdf")
5
+ @rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20.xml")
6
+ @rss20_utf8 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20_utf8.xml")
7
+ @media_rss = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/media_rss.xml")
8
+ @atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom.xml")
9
+ end
10
+
11
+ def test_channel
12
+ assert_equal @rss09, @rss09.channel
13
+ assert_equal @rss20, @rss20.channel
14
+ assert_equal @atom, @atom.feed
15
+ end
16
+
17
+ def test_items
18
+ assert_kind_of Array, @rss09.items
19
+ assert_kind_of Array, @rss20.items
20
+ assert_kind_of Array, @atom.entries
21
+ end
22
+
23
+ def test_rss09
24
+ assert_equal 10, @rss09.items.size
25
+ assert_equal "Slashdot", @rss09.title
26
+ assert_equal "http://slashdot.org/", @rss09.channel.link
27
+ assert_equal "http://books.slashdot.org/article.pl?sid=05/08/29/1319236&amp;from=rss", @rss09.items.first.link
28
+ assert_equal "http://books.slashdot.org/article.pl?sid=05/08/29/1319236&amp;from=rss", @rss09.items.first[:link]
30
29
  assert_equal Time.parse("Wed Aug 24 13:33:34 UTC 2005"), @rss20.items.first.pubDate
31
30
  assert_equal Time.parse("Fri Sep 09 02:52:31 PDT 2005"), @rss09.channel.dc_date
32
- end
31
+ end
32
+
33
+ def test_media_rss
34
+ assert_equal 20, @media_rss.items.size
35
+ assert_equal "Uploads from herval", @media_rss.title
36
+ assert_equal "http://www.flickr.com/photos/herval/", @media_rss.channel.link
37
+ assert_equal "http://www.flickr.com/photos/herval/4671960608/", @media_rss.items.first.link
38
+ assert_equal "http://www.flickr.com/photos/herval/4671960608/", @media_rss.items.first[:link]
39
+ assert_equal "http://farm5.static.flickr.com/4040/4671960608_10cb945d5c_o.jpg", @media_rss.items.first.media_content_url
40
+ assert_equal "image/jpeg", @media_rss.items.first.media_content_type
41
+ assert_equal "3168", @media_rss.items.first.media_content_height
42
+ assert_equal "4752", @media_rss.items.first.media_content_width
43
+ assert_equal "Woof?", @media_rss.items.first.media_title
44
+ assert_equal "http://farm5.static.flickr.com/4040/4671960608_954d2297bc_s.jpg", @media_rss.items.first.media_thumbnail_url
45
+ assert_equal "75", @media_rss.items.first.media_thumbnail_height
46
+ assert_equal "75", @media_rss.items.first.media_thumbnail_width
47
+ assert_equal "herval", @media_rss.items.first.media_credit
48
+ assert_equal "photographer", @media_rss.items.first.media_credit_role
49
+ assert_equal "pets frodo", @media_rss.items.first.media_category
50
+ assert_equal "urn:flickr:tags", @media_rss.items.first.media_category_scheme
51
+ end
52
+
53
+ def test_rss20
54
+ assert_equal 10, @rss20.items.size
55
+ assert_equal "Technoblog", @rss20.title
56
+ assert_equal "http://tech.rufy.com", @rss20.channel.link
57
+ assert_equal "http://feeds.feedburner.com/rufytech?m=68", @rss20.items.first.link
58
+ assert_equal "http://feeds.feedburner.com/rufytech?m=68", @rss20.items.first[:link]
59
+ assert_equal "This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site.", @rss20.channel.feedburner_browserFriendly
60
+ end
61
+
62
+ def test_atom
63
+ assert_equal 1, @atom.entries.size
64
+ assert_equal "dive into mark", @atom.title
65
+ assert_equal "http://example.org/", @atom.feed.link
66
+ assert_equal "http://example.org/2005/04/02/atom", @atom.entries.first.link
67
+ assert_equal "http://example.org/2005/04/02/atom", @atom.entries.first[:link]
68
+ end
33
69
 
34
- def test_media_rss
35
- assert_equal 20, @media_rss.items.size
36
- assert_equal "Uploads from herval", @media_rss.title
37
- assert_equal "http://www.flickr.com/photos/herval/", @media_rss.channel.link
38
- assert_equal "http://www.flickr.com/photos/herval/4671960608/", @media_rss.items.first.link
39
- assert_equal "http://www.flickr.com/photos/herval/4671960608/", @media_rss.items.first[:link]
40
- assert_equal "http://farm5.static.flickr.com/4040/4671960608_10cb945d5c_o.jpg", @media_rss.items.first.media_content_url
41
- assert_equal "image/jpeg", @media_rss.items.first.media_content_type
42
- assert_equal "3168", @media_rss.items.first.media_content_height
43
- assert_equal "4752", @media_rss.items.first.media_content_width
44
- assert_equal "Woof?", @media_rss.items.first.media_title
45
- assert_equal "http://farm5.static.flickr.com/4040/4671960608_954d2297bc_s.jpg", @media_rss.items.first.media_thumbnail_url
46
- assert_equal "75", @media_rss.items.first.media_thumbnail_height
47
- assert_equal "75", @media_rss.items.first.media_thumbnail_width
48
- assert_equal "herval", @media_rss.items.first.media_credit
49
- assert_equal "photographer", @media_rss.items.first.media_credit_role
50
- assert_equal "pets frodo", @media_rss.items.first.media_category
51
- assert_equal "urn:flickr:tags", @media_rss.items.first.media_category_scheme
52
- end
53
-
54
- def test_rss20
55
- assert_equal 10, @rss20.items.size
56
- assert_equal "Technoblog", @rss20.title
57
- assert_equal "http://tech.rufy.com", @rss20.channel.link
58
- assert_equal "http://feeds.feedburner.com/rufytech?m=68", @rss20.items.first.link
59
- assert_equal "http://feeds.feedburner.com/rufytech?m=68", @rss20.items.first[:link]
60
- assert_equal "This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site.", @rss20.channel.feedburner_browserFriendly
61
- end
62
-
63
- def test_atom
64
- assert_equal 1, @atom.entries.size
65
- assert_equal "dive into mark", @atom.title
66
- assert_equal "http://example.org/", @atom.feed.link
67
- assert_equal "http://example.org/2005/04/02/atom", @atom.entries.first.link
68
- assert_equal "http://example.org/2005/04/02/atom", @atom.entries.first[:link]
69
- end
70
-
71
- def test_bad_feed
72
- assert_raise(SimpleRSSError) { SimpleRSS.parse(open(File.dirname(__FILE__) + '/../data/not-rss.xml')) }
73
- end
70
+ def test_bad_feed
71
+ assert_raise(SimpleRSSError) { SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/not-rss.xml")) }
72
+ end
74
73
 
75
- def test_rss_utf8
76
- assert_equal 2, @rss20_utf8.items.size
77
- assert_equal "SC5 Blog", @rss20_utf8.title
78
- assert_equal Encoding::UTF_8, @rss20_utf8.title.encoding
79
- item = @rss20_utf8.items.first
80
- assert_equal "Mitä asiakkaamme ajattelevat meistä?", item.title
81
- assert_equal Encoding::UTF_8, item.title.encoding
82
- end
74
+ def test_rss_utf8
75
+ assert_equal 2, @rss20_utf8.items.size
76
+ assert_equal "SC5 Blog", @rss20_utf8.title
77
+ assert_equal Encoding::UTF_8, @rss20_utf8.title.encoding
78
+ item = @rss20_utf8.items.first
79
+ assert_equal "Mitä asiakkaamme ajattelevat meistä?", item.title
80
+ assert_equal Encoding::UTF_8, item.title.encoding
81
+ end
83
82
  end