logophobia-feedzirra 0.0.15 → 0.0.16
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +9 -0
- data/lib/feedzirra.rb +6 -4
- data/lib/feedzirra/feed.rb +25 -21
- data/lib/feedzirra/parser/itunes_category.rb +12 -0
- data/lib/feedzirra/parser/mrss_content.rb +14 -0
- data/lib/feedzirra/parser/mrss_credit.rb +13 -0
- data/lib/feedzirra/parser/mrss_restriction.rb +13 -0
- data/lib/feedzirra/parser/rss.rb +38 -9
- data/lib/feedzirra/parser/rss_entry.rb +60 -14
- data/lib/feedzirra/parser/rss_image.rb +15 -0
- data/spec/feedzirra/feed_spec.rb +32 -32
- data/spec/feedzirra/parser/rss_entry_spec.rb +121 -8
- data/spec/feedzirra/parser/rss_spec.rb +66 -14
- data/spec/spec_helper.rb +5 -1
- metadata +6 -7
- data/lib/feedzirra/parser/itunes_rss.rb +0 -50
- data/lib/feedzirra/parser/itunes_rss_item.rb +0 -31
- data/lib/feedzirra/parser/itunes_rss_owner.rb +0 -12
- data/spec/feedzirra/parser/itunes_rss_item_spec.rb +0 -48
- data/spec/feedzirra/parser/itunes_rss_owner_spec.rb +0 -18
- data/spec/feedzirra/parser/itunes_rss_spec.rb +0 -50
data/README.textile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
"Changes made from Paul's tree":#changes
|
2
|
+
|
1
3
|
h1. Feedzirra
|
2
4
|
|
3
5
|
"http://github.com/pauldix/feedzirra/tree/master":http://github.com/pauldix/feedzirra/tree/master
|
@@ -168,6 +170,13 @@ Here are some more specific TODOs.
|
|
168
170
|
* Clean up the fetching code inside feed.rb so it doesn't suck so hard.
|
169
171
|
* Readdress how feeds determine if they can parse a document. Maybe I should use namespaces instead?
|
170
172
|
|
173
|
+
h2(#changes). Updates from Paul's tree
|
174
|
+
|
175
|
+
* Add in Media RSS support that should handle the spec with multiple content entries.
|
176
|
+
* Add in the missing support for nested iTunes Categories
|
177
|
+
* Combined iTunes into RSS, removed extra files
|
178
|
+
* Made element names more consistent across RSS and iTunes
|
179
|
+
|
171
180
|
h2. LICENSE
|
172
181
|
|
173
182
|
(The MIT License)
|
data/lib/feedzirra.rb
CHANGED
@@ -11,6 +11,7 @@ require 'active_support/basic_object'
|
|
11
11
|
require 'active_support/core_ext/object'
|
12
12
|
require 'active_support/core_ext/time'
|
13
13
|
|
14
|
+
|
14
15
|
require 'core_ext/date'
|
15
16
|
require 'core_ext/string'
|
16
17
|
|
@@ -19,16 +20,17 @@ require 'feedzirra/feed_entry_utilities'
|
|
19
20
|
require 'feedzirra/feed'
|
20
21
|
|
21
22
|
require 'feedzirra/parser/rss_entry'
|
22
|
-
require 'feedzirra/parser/
|
23
|
-
require 'feedzirra/parser/
|
23
|
+
require 'feedzirra/parser/rss_image'
|
24
|
+
require 'feedzirra/parser/mrss_content'
|
25
|
+
require 'feedzirra/parser/mrss_restriction'
|
26
|
+
require 'feedzirra/parser/itunes_category'
|
24
27
|
require 'feedzirra/parser/atom_entry'
|
25
28
|
require 'feedzirra/parser/atom_feed_burner_entry'
|
26
29
|
|
27
30
|
require 'feedzirra/parser/rss'
|
28
|
-
require 'feedzirra/parser/itunes_rss'
|
29
31
|
require 'feedzirra/parser/atom'
|
30
32
|
require 'feedzirra/parser/atom_feed_burner'
|
31
33
|
|
32
34
|
module Feedzirra
|
33
35
|
VERSION = "0.0.15"
|
34
|
-
end
|
36
|
+
end
|
data/lib/feedzirra/feed.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Feedzirra
|
2
2
|
class NoParserAvailable < StandardError; end
|
3
|
-
|
3
|
+
|
4
4
|
class Feed
|
5
5
|
USER_AGENT = "feedzirra http://github.com/pauldix/feedzirra/tree/master"
|
6
|
-
|
6
|
+
|
7
7
|
# Takes a raw XML feed and attempts to parse it. If no parser is available a Feedzirra::NoParserAvailable exception is raised.
|
8
8
|
#
|
9
9
|
# === Parameters
|
@@ -21,7 +21,7 @@ module Feedzirra
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Determines the correct parser class to use for parsing the feed.
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# === Parameters
|
26
26
|
# [xml<String>] The XML that you would like determine the parser for.
|
27
27
|
# === Returns
|
@@ -37,7 +37,7 @@ module Feedzirra
|
|
37
37
|
# [klass<Constant>] The class/constant that you want to register.
|
38
38
|
# === Returns
|
39
39
|
# A updated array of feed parser class names.
|
40
|
-
def self.add_feed_class(klass)
|
40
|
+
def self.add_feed_class(klass)
|
41
41
|
feed_classes.unshift klass
|
42
42
|
end
|
43
43
|
|
@@ -46,10 +46,14 @@ module Feedzirra
|
|
46
46
|
# === Returns
|
47
47
|
# A array of class names.
|
48
48
|
def self.feed_classes
|
49
|
-
@feed_classes ||= [
|
49
|
+
@feed_classes ||= [
|
50
|
+
Feedzirra::Parser::RSS,
|
51
|
+
Feedzirra::Parser::AtomFeedBurner,
|
52
|
+
Feedzirra::Parser::Atom
|
53
|
+
]
|
50
54
|
end
|
51
|
-
|
52
|
-
# Makes all entry types look for the passed in element to parse. This is actually just a call to
|
55
|
+
|
56
|
+
# Makes all entry types look for the passed in element to parse. This is actually just a call to
|
53
57
|
# element (a SAXMachine call) in the class
|
54
58
|
#
|
55
59
|
# === Parameters
|
@@ -62,7 +66,7 @@ module Feedzirra
|
|
62
66
|
klass.send(:element, element_tag, options)
|
63
67
|
end
|
64
68
|
end
|
65
|
-
|
69
|
+
|
66
70
|
# Fetches and returns the raw XML for each URL provided.
|
67
71
|
#
|
68
72
|
# === Parameters
|
@@ -75,7 +79,7 @@ module Feedzirra
|
|
75
79
|
# :on_failure - Block that gets executed after a failed request.
|
76
80
|
# === Returns
|
77
81
|
# A String of XML if a single URL is passed.
|
78
|
-
#
|
82
|
+
#
|
79
83
|
# A Hash if multiple URL's are passed. The key will be the URL, and the value the XML.
|
80
84
|
def self.fetch_raw(urls, options = {})
|
81
85
|
url_queue = [*urls]
|
@@ -127,13 +131,13 @@ module Feedzirra
|
|
127
131
|
url_queue = [*urls]
|
128
132
|
multi = Curl::Multi.new
|
129
133
|
responses = {}
|
130
|
-
|
134
|
+
|
131
135
|
# I broke these down so I would only try to do 30 simultaneously because
|
132
136
|
# I was getting weird errors when doing a lot. As one finishes it pops another off the queue.
|
133
137
|
url_queue.slice!(0, 30).each do |url|
|
134
138
|
add_url_to_multi(multi, url, url_queue, responses, options)
|
135
139
|
end
|
136
|
-
|
140
|
+
|
137
141
|
multi.perform
|
138
142
|
return urls.is_a?(String) ? responses.values.first : responses
|
139
143
|
end
|
@@ -150,7 +154,7 @@ module Feedzirra
|
|
150
154
|
gz = Zlib::GzipReader.new(StringIO.new(c.body_str))
|
151
155
|
xml = gz.read
|
152
156
|
gz.close
|
153
|
-
rescue Zlib::GzipFile::Error
|
157
|
+
rescue Zlib::GzipFile::Error
|
154
158
|
# Maybe this is not gzipped?
|
155
159
|
xml = c.body_str
|
156
160
|
end
|
@@ -179,15 +183,15 @@ module Feedzirra
|
|
179
183
|
feed_queue = [*feeds]
|
180
184
|
multi = Curl::Multi.new
|
181
185
|
responses = {}
|
182
|
-
|
186
|
+
|
183
187
|
feed_queue.slice!(0, 30).each do |feed|
|
184
188
|
add_feed_to_multi(multi, feed, feed_queue, responses, options)
|
185
189
|
end
|
186
|
-
|
190
|
+
|
187
191
|
multi.perform
|
188
192
|
responses.size == 1 ? responses.values.first : responses.values
|
189
193
|
end
|
190
|
-
|
194
|
+
|
191
195
|
# An abstraction for adding a feed by URL to the passed Curb::multi stack.
|
192
196
|
#
|
193
197
|
# === Parameters
|
@@ -219,7 +223,7 @@ module Feedzirra
|
|
219
223
|
add_url_to_multi(multi, url_queue.shift, url_queue, responses, options) unless url_queue.empty?
|
220
224
|
xml = decode_content(c)
|
221
225
|
klass = determine_feed_parser_for_xml(xml)
|
222
|
-
|
226
|
+
|
223
227
|
if klass
|
224
228
|
begin
|
225
229
|
feed = klass.parse(xml)
|
@@ -237,7 +241,7 @@ module Feedzirra
|
|
237
241
|
options[:on_failure].call(url, c.response_code, c.header_str, c.body_str) if options.has_key?(:on_failure)
|
238
242
|
end
|
239
243
|
end
|
240
|
-
|
244
|
+
|
241
245
|
curl.on_failure do |c|
|
242
246
|
c = c.select { |e| e.kind_of? Curl::Easy }.first if(c.kind_of? Array)
|
243
247
|
add_url_to_multi(multi, url_queue.shift, url_queue, responses, options) unless url_queue.empty?
|
@@ -247,7 +251,7 @@ module Feedzirra
|
|
247
251
|
end
|
248
252
|
multi.add(easy)
|
249
253
|
end
|
250
|
-
|
254
|
+
|
251
255
|
# An abstraction for adding a feed by a Feed object to the passed Curb::multi stack.
|
252
256
|
#
|
253
257
|
# === Parameters
|
@@ -262,7 +266,7 @@ module Feedzirra
|
|
262
266
|
# * :on_failure - Block that gets executed after a failed request.
|
263
267
|
# === Returns
|
264
268
|
# The updated Curl::Multi object with the request details added to it's stack.
|
265
|
-
def self.add_feed_to_multi(multi, feed, feed_queue, responses, options)
|
269
|
+
def self.add_feed_to_multi(multi, feed, feed_queue, responses, options)
|
266
270
|
easy = Curl::Easy.new(feed.feed_url) do |curl|
|
267
271
|
curl.headers["User-Agent"] = (options[:user_agent] || USER_AGENT)
|
268
272
|
curl.headers["If-Modified-Since"] = feed.last_modified.httpdate if feed.last_modified
|
@@ -306,7 +310,7 @@ module Feedzirra
|
|
306
310
|
end
|
307
311
|
|
308
312
|
# Determines the etag from the request headers.
|
309
|
-
#
|
313
|
+
#
|
310
314
|
# === Parameters
|
311
315
|
# [header<String>] Raw request header returned from the request
|
312
316
|
# === Returns
|
@@ -327,4 +331,4 @@ module Feedzirra
|
|
327
331
|
Time.parse($1) if $1
|
328
332
|
end
|
329
333
|
end
|
330
|
-
end
|
334
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Feedzirra
|
2
|
+
module Parser
|
3
|
+
class RSSEntry
|
4
|
+
class MRSSContent
|
5
|
+
include SAXMachine
|
6
|
+
|
7
|
+
element :'media:content', :as => :url, :value => :url
|
8
|
+
element :'media:content', :as => :content_type, :value => :type
|
9
|
+
element :'media:content', :as => :medium, :value => :medium
|
10
|
+
element :'media:content', :as => :duration, :value => :duration
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Feedzirra
|
2
|
+
module Parser
|
3
|
+
class RSSEntry
|
4
|
+
class MRSSCredit
|
5
|
+
include SAXMachine
|
6
|
+
|
7
|
+
element :'media:credit', :as => :role, :value => :role
|
8
|
+
element :'media:credit', :as => :scheme, :value => :scheme
|
9
|
+
element :'media:credit', :as => :name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Feedzirra
|
2
|
+
module Parser
|
3
|
+
class RSSEntry
|
4
|
+
class MRSSRestriction
|
5
|
+
include SAXMachine
|
6
|
+
|
7
|
+
element :'media:restriction', :as => :value
|
8
|
+
element :'media:restriction', :as => :scope, :value => :type
|
9
|
+
element :'media:restriction', :as => :relationship, :value => :relationship
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/feedzirra/parser/rss.rb
CHANGED
@@ -1,28 +1,57 @@
|
|
1
1
|
module Feedzirra
|
2
|
-
|
3
2
|
module Parser
|
4
3
|
# == Summary
|
5
4
|
# Parser for dealing with RSS feeds.
|
6
5
|
#
|
7
|
-
# == Attributes
|
8
|
-
# * title
|
9
|
-
# * feed_url
|
10
|
-
# * url
|
11
|
-
# * entries
|
12
6
|
class RSS
|
13
7
|
include SAXMachine
|
14
8
|
include FeedUtilities
|
9
|
+
|
10
|
+
attr_accessor :feed_url
|
11
|
+
|
12
|
+
# RSS 2.0 required elements
|
15
13
|
element :title
|
16
14
|
element :link, :as => :url
|
15
|
+
element :description
|
17
16
|
elements :item, :as => :entries, :class => RSSEntry
|
18
17
|
|
19
|
-
|
18
|
+
# RSS 2.0 optional elements
|
19
|
+
element :language
|
20
|
+
element :copyright
|
21
|
+
element :managingEditor
|
22
|
+
element :webMaster
|
23
|
+
element :pubDate
|
24
|
+
element :lastBuildDate
|
25
|
+
element :category
|
26
|
+
element :generator
|
27
|
+
element :docs
|
28
|
+
element :cloud
|
29
|
+
element :ttl
|
30
|
+
element :image, :class => RSSImage
|
31
|
+
element :rating
|
32
|
+
element :textInput
|
33
|
+
element :skipHours
|
34
|
+
element :skipDays
|
35
|
+
|
36
|
+
# iTunes
|
37
|
+
element :'itunes:author', :as => :author
|
38
|
+
element :'itunes:block', :as => :itunes_block
|
39
|
+
element :'itunes:image', :as => :image, :value => :href
|
40
|
+
element :'itunes:explicit', :as => :explicit
|
41
|
+
element :'itunes:keywords', :as => :keywords
|
42
|
+
element :'itunes:new-feed-url', :as => :feed_url
|
43
|
+
element :'itunes:name', :as => :owner_name
|
44
|
+
element :'itunes:email', :as => :owner_email
|
45
|
+
element :'itunes:subtitle', :as => :subtitle
|
46
|
+
element :'itunes:summary', :as => :summary
|
47
|
+
|
48
|
+
elements :'itunes:category', :as => :categories, :value => :text
|
49
|
+
# elements :'itunes:category', :as => :itunes_categories,
|
50
|
+
# :class => ITunesCategory
|
20
51
|
|
21
52
|
def self.able_to_parse?(xml) #:nodoc:
|
22
53
|
xml =~ /\<rss|rdf/
|
23
54
|
end
|
24
55
|
end
|
25
|
-
|
26
56
|
end
|
27
|
-
|
28
57
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/mrss_content'
|
2
|
+
require File.dirname(__FILE__) + '/mrss_credit'
|
3
|
+
require File.dirname(__FILE__) + '/mrss_restriction'
|
4
|
+
|
1
5
|
module Feedzirra
|
2
|
-
|
3
6
|
module Parser
|
4
7
|
# == Summary
|
5
8
|
# Parser for dealing with RDF feed entries.
|
@@ -15,28 +18,71 @@ module Feedzirra
|
|
15
18
|
class RSSEntry
|
16
19
|
include SAXMachine
|
17
20
|
include FeedEntryUtilities
|
21
|
+
|
22
|
+
# RSS 2.0 elements
|
18
23
|
element :title
|
19
24
|
element :link, :as => :url
|
20
|
-
|
21
|
-
element :"dc:creator", :as => :author
|
22
|
-
element :author, :as => :author
|
23
|
-
element :"content:encoded", :as => :content
|
24
25
|
element :description, :as => :summary
|
25
|
-
|
26
|
+
element :author
|
27
|
+
elements :category, :as => :categories
|
28
|
+
element :comments
|
29
|
+
element :guid, :as => :id
|
26
30
|
element :pubDate, :as => :published
|
27
|
-
element :
|
31
|
+
element :source
|
32
|
+
element :enclosure, :value => :length, :as => :enclosure_length
|
33
|
+
element :enclosure, :value => :type, :as => :enclosure_type
|
34
|
+
element :enclosure, :value => :url, :as => :enclosure_url
|
35
|
+
|
36
|
+
|
37
|
+
# RDF elements
|
28
38
|
element :"dc:date", :as => :published
|
29
39
|
element :"dc:Date", :as => :published
|
30
40
|
element :"dcterms:created", :as => :published
|
41
|
+
element :issued, :as => :published
|
42
|
+
element :"content:encoded", :as => :content
|
43
|
+
element :"dc:creator", :as => :author
|
44
|
+
element :"dcterms:modified", :as => :updated
|
31
45
|
|
46
|
+
# MediaRSS support
|
47
|
+
element :'media:thumbnail', :as => :media_thumbnail, :value => :url
|
48
|
+
element :'media:thumbnail', :as => :media_thumbnail_width, :value => :width
|
49
|
+
element :'media:thumbnail', :as => :media_thumbnail_height, :value => :height
|
50
|
+
element :'media:description', :as => :media_description
|
32
51
|
|
33
|
-
element :
|
34
|
-
element :
|
35
|
-
elements :category, :as => :categories
|
52
|
+
element :'media:rating', :as => :rating
|
53
|
+
element :'media:rating', :value => :scheme, :as => :rating_scheme
|
36
54
|
|
37
|
-
element :
|
38
|
-
|
55
|
+
element :'media:title', :as => :media_title
|
56
|
+
element :'media:keywords', :as => :media_keywords
|
57
|
+
|
58
|
+
element :'media:category', :as => :media_category
|
59
|
+
element :'media:category', :value => :scheme, :as => :media_category_scheme
|
60
|
+
element :'media:category', :value => :label, :as => :media_category_label
|
61
|
+
|
62
|
+
element :'media:hash', :as => :media_hash
|
63
|
+
element :'media:hash', :value => :algo, :as => :media_hash_algo
|
39
64
|
|
65
|
+
element :'media:player', :value => :url, :as => :media_player_url
|
66
|
+
element :'media:player', :value => :width, :as => :media_player_width
|
67
|
+
element :'media:player', :value => :height, :as => :media_player_height
|
68
|
+
|
69
|
+
elements :'media:credit', :as => :credits, :class => MRSSCredit
|
70
|
+
|
71
|
+
element :'media:copyright', :as => :copyright
|
72
|
+
element :'media:copyright', :as => :copyright_url, :value => :url
|
73
|
+
|
74
|
+
element :'media:restriction', :as => :media_restriction, :class => MRSSRestriction
|
75
|
+
|
76
|
+
elements :'media:content', :as => :media_content, :class => MRSSContent
|
77
|
+
|
78
|
+
# iTunes
|
79
|
+
element :'itunes:author', :as => :author
|
80
|
+
element :'itunes:block', :as => :itunes_block
|
81
|
+
element :'itunes:duration', :as => :duration
|
82
|
+
element :'itunes:explicit', :as => :explicit
|
83
|
+
element :'itunes:keywords', :as => :keywords
|
84
|
+
element :'itunes:subtitle', :as => :subtitle
|
85
|
+
element :'itunes:summary', :as => :summary
|
86
|
+
end
|
40
87
|
end
|
41
|
-
|
42
|
-
end
|
88
|
+
end
|
data/spec/feedzirra/feed_spec.rb
CHANGED
@@ -5,20 +5,20 @@ describe Feedzirra::Feed do
|
|
5
5
|
before(:all) do
|
6
6
|
Feedzirra::Feed.add_common_feed_entry_element("wfw:commentRss", :as => :comment_rss)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
it "should parse the added element out of Atom feeds" do
|
10
10
|
Feedzirra::Feed.parse(sample_wfw_feed).entries.first.comment_rss.should == "this is the new val"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "should parse the added element out of Atom Feedburner feeds" do
|
14
14
|
Feedzirra::Parser::AtomEntry.new.should respond_to(:comment_rss)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should parse the added element out of RSS feeds" do
|
18
18
|
Feedzirra::Parser::RSSEntry.new.should respond_to(:comment_rss)
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
describe "#parse" do # many of these tests are redundant with the specific feed type tests, but I put them here for completeness
|
23
23
|
context "when there's an available parser" do
|
24
24
|
it "should parse an rdf feed" do
|
@@ -47,17 +47,17 @@ describe Feedzirra::Feed do
|
|
47
47
|
feed.title.should == "Paul Dix Explains Nothing"
|
48
48
|
feed.entries.first.published.to_s.should == "Thu Jan 22 15:50:22 UTC 2009"
|
49
49
|
feed.entries.size.should == 5
|
50
|
-
end
|
50
|
+
end
|
51
51
|
|
52
52
|
it "should parse an itunes feed as a standard RSS feed" do
|
53
53
|
feed = Feedzirra::Feed.parse(sample_itunes_feed)
|
54
54
|
feed.title.should == "All About Everything"
|
55
55
|
feed.entries.first.published.should == Time.parse("Wed, 15 Jun 2005 19:00:00 GMT")
|
56
|
-
|
56
|
+
|
57
57
|
# Since the commit 621957879, iTunes feeds will be parsed as standard RSS, so this
|
58
58
|
# entry should now not have a method for itunes_author.
|
59
59
|
feed.entries.first.should_not respond_to(:itunes_author)
|
60
|
-
feed.entries.size.should ==
|
60
|
+
feed.entries.size.should == 4
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -113,7 +113,7 @@ describe Feedzirra::Feed do
|
|
113
113
|
true
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
new_feed_type.should be_able_to_parse(feed_text)
|
118
118
|
Feedzirra::Feed.add_feed_class(new_feed_type)
|
119
119
|
Feedzirra::Feed.determine_feed_parser_for_xml(feed_text).should == new_feed_type
|
@@ -165,7 +165,7 @@ describe Feedzirra::Feed do
|
|
165
165
|
@curl_easy = stub('curl_easy')
|
166
166
|
@curl = stub('curl', :headers => {}, :follow_location= => true, :on_failure => true)
|
167
167
|
@curl.stub!(:on_success).and_yield(@cmock)
|
168
|
-
|
168
|
+
|
169
169
|
Curl::Multi.stub!(:new).and_return(@multi)
|
170
170
|
Curl::Easy.stub!(:new).and_yield(@curl).and_return(@curl_easy)
|
171
171
|
end
|
@@ -179,7 +179,7 @@ describe Feedzirra::Feed do
|
|
179
179
|
Feedzirra::Feed.fetch_raw(@paul_feed[:url])
|
180
180
|
@curl.headers['User-Agent'].should == Feedzirra::Feed::USER_AGENT
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
it "should set if modified since as an option if passed" do
|
184
184
|
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_modified_since => Time.parse("Wed, 28 Jan 2009 04:10:32 GMT"))
|
185
185
|
@curl.headers["If-Modified-Since"].should == 'Wed, 28 Jan 2009 04:10:32 GMT'
|
@@ -189,7 +189,7 @@ describe Feedzirra::Feed do
|
|
189
189
|
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
|
190
190
|
@curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
it 'should set userpwd for http basic authentication if :http_authentication is passed' do
|
194
194
|
@curl.should_receive(:userpwd=).with('username:password')
|
195
195
|
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :http_authentication => ['username', 'password'])
|
@@ -207,7 +207,7 @@ describe Feedzirra::Feed do
|
|
207
207
|
it "should take multiple feed urls and return a hash of urls and response xml" do
|
208
208
|
multi = stub('curl_multi', :add => true, :perform => true)
|
209
209
|
Curl::Multi.stub!(:new).and_return(multi)
|
210
|
-
|
210
|
+
|
211
211
|
paul_response = stub('paul_response', :header_str => '', :body_str => @paul_feed[:xml] )
|
212
212
|
trotter_response = stub('trotter_response', :header_str => '', :body_str => @trotter_feed[:xml] )
|
213
213
|
|
@@ -216,10 +216,10 @@ describe Feedzirra::Feed do
|
|
216
216
|
|
217
217
|
trotter_curl = stub('trotter_curl', :headers => {}, :follow_location= => true, :on_failure => true)
|
218
218
|
trotter_curl.stub!(:on_success).and_yield(trotter_response)
|
219
|
-
|
219
|
+
|
220
220
|
Curl::Easy.should_receive(:new).with(@paul_feed[:url]).ordered.and_yield(paul_curl)
|
221
221
|
Curl::Easy.should_receive(:new).with(@trotter_feed[:url]).ordered.and_yield(trotter_curl)
|
222
|
-
|
222
|
+
|
223
223
|
results = Feedzirra::Feed.fetch_raw([@paul_feed[:url], @trotter_feed[:url]])
|
224
224
|
results.keys.should include(@paul_feed[:url])
|
225
225
|
results.keys.should include(@trotter_feed[:url])
|
@@ -238,7 +238,7 @@ describe Feedzirra::Feed do
|
|
238
238
|
@multi = Curl::Multi.new(@paul_feed[:url])
|
239
239
|
@multi.stub!(:add)
|
240
240
|
@easy_curl = Curl::Easy.new(@paul_feed[:url])
|
241
|
-
|
241
|
+
|
242
242
|
Curl::Easy.should_receive(:new).and_yield(@easy_curl)
|
243
243
|
end
|
244
244
|
|
@@ -246,12 +246,12 @@ describe Feedzirra::Feed do
|
|
246
246
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :user_agent => 'My cool application')
|
247
247
|
@easy_curl.headers["User-Agent"].should == 'My cool application'
|
248
248
|
end
|
249
|
-
|
249
|
+
|
250
250
|
it "should set user agent to default if it's not passed as an option" do
|
251
251
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
252
252
|
@easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
|
253
253
|
end
|
254
|
-
|
254
|
+
|
255
255
|
it "should set if modified since as an option if passed" do
|
256
256
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_modified_since => Time.parse("Jan 25 2009 04:10:32 GMT"))
|
257
257
|
@easy_curl.headers["If-Modified-Since"].should == 'Sun, 25 Jan 2009 04:10:32 GMT'
|
@@ -261,12 +261,12 @@ describe Feedzirra::Feed do
|
|
261
261
|
@easy_curl.should_receive(:follow_location=).with(true)
|
262
262
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
263
263
|
end
|
264
|
-
|
264
|
+
|
265
265
|
it 'should set userpwd for http basic authentication if :http_authentication is passed' do
|
266
266
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :http_authentication => ['myusername', 'mypassword'])
|
267
267
|
@easy_curl.userpwd.should == 'myusername:mypassword'
|
268
268
|
end
|
269
|
-
|
269
|
+
|
270
270
|
it 'should set accepted encodings' do
|
271
271
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {:compress => true})
|
272
272
|
@easy_curl.headers["Accept-encoding"].should == 'gzip, deflate'
|
@@ -276,7 +276,7 @@ describe Feedzirra::Feed do
|
|
276
276
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
|
277
277
|
@easy_curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
278
278
|
end
|
279
|
-
|
279
|
+
|
280
280
|
describe 'on success' do
|
281
281
|
before(:each) do
|
282
282
|
@feed = mock('feed', :feed_url= => true, :etag= => true, :last_modified= => true)
|
@@ -292,7 +292,7 @@ describe Feedzirra::Feed do
|
|
292
292
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
293
293
|
@easy_curl.on_success.call(@easy_curl)
|
294
294
|
end
|
295
|
-
|
295
|
+
|
296
296
|
it 'should determine the xml parser class' do
|
297
297
|
Feedzirra::Feed.should_receive(:determine_feed_parser_for_xml).with(@paul_feed[:xml]).and_return(Feedzirra::Parser::AtomFeedBurner)
|
298
298
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
@@ -304,7 +304,7 @@ describe Feedzirra::Feed do
|
|
304
304
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
305
305
|
@easy_curl.on_success.call(@easy_curl)
|
306
306
|
end
|
307
|
-
|
307
|
+
|
308
308
|
describe 'when a compatible xml parser class is found' do
|
309
309
|
it 'should set the last effective url to the feed url' do
|
310
310
|
@easy_curl.should_receive(:last_effective_url).and_return(@paul_feed[:url])
|
@@ -329,11 +329,11 @@ describe Feedzirra::Feed do
|
|
329
329
|
responses = {}
|
330
330
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
|
331
331
|
@easy_curl.on_success.call(@easy_curl)
|
332
|
-
|
332
|
+
|
333
333
|
responses.length.should == 1
|
334
334
|
responses['http://feeds.feedburner.com/PaulDixExplainsNothing'].should == @feed
|
335
335
|
end
|
336
|
-
|
336
|
+
|
337
337
|
it 'should call proc if :on_success option is passed' do
|
338
338
|
success = lambda { |url, feed| }
|
339
339
|
success.should_receive(:call).with(@paul_feed[:url], @feed)
|
@@ -363,7 +363,7 @@ describe Feedzirra::Feed do
|
|
363
363
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_failure => failure })
|
364
364
|
@easy_curl.on_failure.call(@easy_curl)
|
365
365
|
end
|
366
|
-
|
366
|
+
|
367
367
|
it 'should return the http code in the responses' do
|
368
368
|
responses = {}
|
369
369
|
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
|
@@ -389,14 +389,14 @@ describe Feedzirra::Feed do
|
|
389
389
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, :user_agent => 'My cool application')
|
390
390
|
@easy_curl.headers["User-Agent"].should == 'My cool application'
|
391
391
|
end
|
392
|
-
|
392
|
+
|
393
393
|
it "should set user agent to default if it's not passed as an option" do
|
394
394
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
395
395
|
@easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
|
396
396
|
end
|
397
397
|
|
398
398
|
it "should set if modified since as an option if passed"
|
399
|
-
|
399
|
+
|
400
400
|
it 'should set follow location to true' do
|
401
401
|
@easy_curl.should_receive(:follow_location=).with(true)
|
402
402
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
@@ -425,7 +425,7 @@ describe Feedzirra::Feed do
|
|
425
425
|
end
|
426
426
|
|
427
427
|
it 'should process the next feed in the queue'
|
428
|
-
|
428
|
+
|
429
429
|
it 'should parse the updated feed' do
|
430
430
|
Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).and_return(@new_feed)
|
431
431
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
@@ -466,7 +466,7 @@ describe Feedzirra::Feed do
|
|
466
466
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
|
467
467
|
@easy_curl.on_success.call(@easy_curl)
|
468
468
|
end
|
469
|
-
|
469
|
+
|
470
470
|
it 'should call update from feed on the old feed with the updated feed' do
|
471
471
|
@feed.should_receive(:update_from_feed).with(@new_feed)
|
472
472
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
@@ -491,7 +491,7 @@ describe Feedzirra::Feed do
|
|
491
491
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
|
492
492
|
@easy_curl.on_failure.call(@easy_curl)
|
493
493
|
end
|
494
|
-
|
494
|
+
|
495
495
|
it 'should return the http code in the responses' do
|
496
496
|
responses = {}
|
497
497
|
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], responses, {})
|
@@ -523,7 +523,7 @@ describe Feedzirra::Feed do
|
|
523
523
|
Zlib::GzipReader.should_receive(:new).with(string_io).and_return(string_io)
|
524
524
|
Feedzirra::Feed.decode_content(@curl_easy)
|
525
525
|
end
|
526
|
-
|
526
|
+
|
527
527
|
it 'should deflate the response body using inflate if the Content-Encoding: is deflate' do
|
528
528
|
@curl_easy.stub!(:header_str).and_return('Content-Encoding: deflate')
|
529
529
|
Zlib::Inflate.should_receive(:inflate).with(@curl_easy.body_str)
|
@@ -540,7 +540,7 @@ describe Feedzirra::Feed do
|
|
540
540
|
it 'should perform the updating using multicurl'
|
541
541
|
it "should pass any request options through to add_feed_to_multi"
|
542
542
|
it "should return a feed object if a single feed is passed in"
|
543
|
-
it "should return an return an array of feed objects if multiple feeds are passed in"
|
543
|
+
it "should return an return an array of feed objects if multiple feeds are passed in"
|
544
544
|
end
|
545
545
|
end
|
546
546
|
end
|
@@ -1,32 +1,32 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
2
|
|
3
3
|
describe Feedzirra::Parser::RSSEntry do
|
4
|
-
before
|
4
|
+
before do
|
5
5
|
# I don't really like doing it this way because these unit test should only rely on RSSEntry,
|
6
6
|
# but this is actually how it should work. You would never just pass entry xml straight to the AtomEnry
|
7
7
|
@entry = Feedzirra::Parser::RSS.parse(sample_rss_feed).entries.first
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
it "should parse the title" do
|
11
11
|
@entry.title.should == "Nokogiri’s Slop Feature"
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
it "should parse the url" do
|
15
15
|
@entry.url.should == "http://tenderlovemaking.com/2008/12/04/nokogiris-slop-feature/"
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
it "should parse the author" do
|
19
19
|
@entry.author.should == "Aaron Patterson"
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it "should parse the content" do
|
23
23
|
@entry.content.should == sample_rss_entry_content
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
it "should provide a summary" do
|
27
27
|
@entry.summary.should == "Oops! When I released nokogiri version 1.0.7, I totally forgot to talk about Nokogiri::Slop() feature that was added. Why is it called \"slop\"? It lets you sloppily explore documents. Basically, it decorates your document with method_missing() that allows you to search your document via method calls.\nGiven this document:\n\ndoc = Nokogiri::Slop(<<-eohtml)\n<html>\n  <body>\n  [...]"
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it "should parse the published date" do
|
31
31
|
@entry.published.to_s.should == "Thu Dec 04 17:17:49 UTC 2008"
|
32
32
|
end
|
@@ -34,8 +34,121 @@ describe Feedzirra::Parser::RSSEntry do
|
|
34
34
|
it "should parse the categories" do
|
35
35
|
@entry.categories.should == ['computadora', 'nokogiri', 'rails']
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
it "should parse the guid as id" do
|
39
39
|
@entry.id.should == "http://tenderlovemaking.com/?p=198"
|
40
40
|
end
|
41
|
+
|
42
|
+
describe "parsing an iTunes feed" do
|
43
|
+
before do
|
44
|
+
@item = Feedzirra::Parser::RSS.parse(sample_itunes_feed).entries.first
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse the title" do
|
48
|
+
@item.title.should == "Shake Shake Shake Your Spices"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse the author" do
|
52
|
+
@item.author.should == "John Doe"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should parse the subtitle" do
|
56
|
+
@item.subtitle.should == "A short primer on table spices"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should parse the summary" do
|
60
|
+
@item.summary.should == "This week we talk about salt and pepper shakers, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse the enclosure" do
|
64
|
+
@item.enclosure_length.should == "8727310"
|
65
|
+
@item.enclosure_type.should == "audio/x-m4a"
|
66
|
+
@item.enclosure_url.should == "http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should parse the id" do
|
70
|
+
@item.id.should == "http://example.com/podcasts/archive/aae20050615.m4a"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should parse the published date" do
|
74
|
+
@item.published.should == Time.parse('Wed Jun 15 19:00:00 UTC 2005')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should parse the duration" do
|
78
|
+
@item.duration.should == "7:04"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should parse the keywords" do
|
82
|
+
@item.keywords.should == "salt, pepper, shaker, exciting"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "parsing Media RSS" do
|
87
|
+
before do
|
88
|
+
@item = Feedzirra::Parser::RSS.parse(sample_mrss_feed).entries.first
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should parse media:rating" do
|
92
|
+
@item.rating.should == 'adult'
|
93
|
+
@item.rating_scheme.should == 'urn:simple'
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should parse media:title" do
|
97
|
+
@item.media_title.should == 'The Montauk Monster-Hells Visits New York!'
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should parse media:description" do
|
101
|
+
@item.media_description.should == 'The story began with a July 23 article in a local newspaper, The Independent. Jenna Hewitt, 26, of Montauk, and three friends said they found the ...'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should parse media:keywords" do
|
105
|
+
@item.media_keywords.should == 'kitty, cat, big dog, yarn, fluffy'
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should parse media:tumbnail" do
|
109
|
+
@item.media_content.size.should == 1
|
110
|
+
@item.media_description.should == 'The story began with a July 23 article in a local newspaper, The Independent. Jenna Hewitt, 26, of Montauk, and three friends said they found the ...'
|
111
|
+
@item.media_thumbnail.should == 'http://3.gvt0.com/vi/Y3rNEu4A8WM/default.jpg'
|
112
|
+
@item.media_thumbnail_width.should == '320'
|
113
|
+
@item.media_thumbnail_height.should == '240'
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should parse media:category" do
|
117
|
+
@item.media_category.should == 'Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_-_Pet_Detective'
|
118
|
+
@item.media_category_scheme.should == 'http://dmoz.org'
|
119
|
+
@item.media_category_label.should == 'Ace Ventura - Pet Detective'
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should parse media:hash" do
|
123
|
+
@item.media_hash.should == 'dfdec888b72151965a34b4b59031290a'
|
124
|
+
@item.media_hash_algo.should == 'md5'
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should parse media:player" do
|
128
|
+
@item.media_player_url.should == 'http://www.example.com/player?id=1111'
|
129
|
+
@item.media_player_width.should == '400'
|
130
|
+
@item.media_player_height.should == '200'
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should parse media:credit" do
|
134
|
+
@item.credits.size.should == 2
|
135
|
+
@item.credits.first.role.should == 'producer'
|
136
|
+
@item.credits.first.scheme.should == 'urn:ebu'
|
137
|
+
pending 'not sure why the name isn\'t getting set'
|
138
|
+
@item.credits.first.name.should == 'John Doe'
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should parse media:copyright" do
|
142
|
+
@item.copyright.should == '2009 Example Co.'
|
143
|
+
@item.copyright_url.should == 'http://example.com/copyright.html'
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should parse media:restriction" do
|
147
|
+
pending 'need to figure out why this is getting String'
|
148
|
+
@item.media_restriction.type.should == 'MRSSRestriction'
|
149
|
+
@item.media_restriction.value.should == 'au us'
|
150
|
+
@item.media_restriction.scope.should == 'country'
|
151
|
+
@item.media_restriction.relationship.should == 'allow'
|
152
|
+
end
|
153
|
+
end
|
41
154
|
end
|
@@ -6,36 +6,88 @@ describe Feedzirra::Parser::RSS do
|
|
6
6
|
Feedzirra::Parser::RSS.should be_able_to_parse(sample_rss_feed)
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
it "should return true for an rdf feed" do
|
10
|
+
Feedzirra::Parser::RSS.should be_able_to_parse(sample_rdf_feed)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return true for an iTunes feed" do
|
14
|
+
Feedzirra::Parser::RSS.should be_able_to_parse(sample_itunes_feed)
|
15
|
+
end
|
16
|
+
|
14
17
|
it "should return fase for an atom feed" do
|
15
18
|
Feedzirra::Parser::RSS.should_not be_able_to_parse(sample_atom_feed)
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
22
|
describe "parsing" do
|
20
|
-
before
|
21
|
-
@feed = Feedzirra::Parser::RSS.parse(
|
23
|
+
before do
|
24
|
+
@feed = Feedzirra::Parser::RSS.parse(sample_mrss_feed)
|
22
25
|
end
|
23
|
-
|
26
|
+
|
24
27
|
it "should parse the title" do
|
25
|
-
@feed.title.should == "
|
28
|
+
@feed.title.should == "Google Video - Hot videos"
|
26
29
|
end
|
27
|
-
|
30
|
+
|
28
31
|
it "should parse the url" do
|
29
|
-
@feed.url.should == "http://
|
32
|
+
@feed.url.should == "http://video.google.com/"
|
30
33
|
end
|
31
|
-
|
34
|
+
|
32
35
|
it "should provide an accessor for the feed_url" do
|
33
36
|
@feed.respond_to?(:feed_url).should == true
|
34
37
|
@feed.respond_to?(:feed_url=).should == true
|
35
38
|
end
|
36
|
-
|
39
|
+
|
37
40
|
it "should parse entries" do
|
38
|
-
@feed.entries.size.should ==
|
41
|
+
@feed.entries.size.should == 20
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should parse the image" do
|
45
|
+
pending 'setting NilClass for some reason'
|
46
|
+
@feed.image.class.should == 'RSSImage'
|
47
|
+
@feed.image.title.should == 'Google Video - Hot videos'
|
48
|
+
@feed.image.link.should == 'http://video.google.com/'
|
49
|
+
@feed.image.url.should == 'http://video.google.com/common/google_logo_small.jpg'
|
50
|
+
@feed.image.width.should == '100'
|
51
|
+
@feed.image.height.should == '37'
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "parsing an iTunes feed" do
|
55
|
+
before do
|
56
|
+
@feed = Feedzirra::Parser::RSS.parse(sample_itunes_feed)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should parse an image" do
|
60
|
+
@feed.image.should == "http://example.com/podcasts/everything/AllAboutEverything.jpg"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse categories" do
|
64
|
+
@feed.categories.size == 2
|
65
|
+
@feed.categories[0].should == "Technology"
|
66
|
+
@feed.categories[1].should == "Gadgets"
|
67
|
+
@feed.categories[2].should == "TV & Film"
|
68
|
+
|
69
|
+
# @feed.categories[0].name.should == "Technology"
|
70
|
+
# @feed.categories[0].sub_categories.size.should == 1
|
71
|
+
# @feed.categories[0].sub_categories[0].should == "Gadgets"
|
72
|
+
# @feed.categories[1].name.should == "TV & Film"
|
73
|
+
# @feed.categories[1].sub_categories.size.should == 0
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should parse the summary" do
|
77
|
+
@feed.summary.should == "All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should parse entries" do
|
81
|
+
@feed.entries.size.should == 4
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should parse the owner name" do
|
85
|
+
@feed.owner_name.should == 'John Doe'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should parse the owner email" do
|
89
|
+
@feed.owner_email.should == 'john.doe@example.com'
|
90
|
+
end
|
39
91
|
end
|
40
92
|
end
|
41
93
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logophobia-feedzirra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Dix
|
@@ -89,11 +89,13 @@ files:
|
|
89
89
|
- lib/feedzirra/parser/atom_entry.rb
|
90
90
|
- lib/feedzirra/parser/atom_feed_burner.rb
|
91
91
|
- lib/feedzirra/parser/atom_feed_burner_entry.rb
|
92
|
-
- lib/feedzirra/parser/
|
93
|
-
- lib/feedzirra/parser/itunes_rss_item.rb
|
94
|
-
- lib/feedzirra/parser/itunes_rss_owner.rb
|
92
|
+
- lib/feedzirra/parser/itunes_category.rb
|
95
93
|
- lib/feedzirra/parser/rss.rb
|
96
94
|
- lib/feedzirra/parser/rss_entry.rb
|
95
|
+
- lib/feedzirra/parser/rss_image.rb
|
96
|
+
- lib/feedzirra/parser/mrss_content.rb
|
97
|
+
- lib/feedzirra/parser/mrss_credit.rb
|
98
|
+
- lib/feedzirra/parser/mrss_restriction.rb
|
97
99
|
- lib/feedzirra/feed_utilities.rb
|
98
100
|
- lib/feedzirra/feed_entry_utilities.rb
|
99
101
|
- README.textile
|
@@ -105,9 +107,6 @@ files:
|
|
105
107
|
- spec/feedzirra/parser/atom_entry_spec.rb
|
106
108
|
- spec/feedzirra/parser/atom_feed_burner_spec.rb
|
107
109
|
- spec/feedzirra/parser/atom_feed_burner_entry_spec.rb
|
108
|
-
- spec/feedzirra/parser/itunes_rss_spec.rb
|
109
|
-
- spec/feedzirra/parser/itunes_rss_item_spec.rb
|
110
|
-
- spec/feedzirra/parser/itunes_rss_owner_spec.rb
|
111
110
|
- spec/feedzirra/parser/rss_spec.rb
|
112
111
|
- spec/feedzirra/parser/rss_entry_spec.rb
|
113
112
|
- spec/feedzirra/feed_utilities_spec.rb
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# iTunes is RSS 2.0 + some apple extensions
|
5
|
-
# Source: http://www.apple.com/itunes/whatson/podcasts/specs.html
|
6
|
-
class ITunesRSS
|
7
|
-
include SAXMachine
|
8
|
-
include FeedUtilities
|
9
|
-
|
10
|
-
attr_accessor :feed_url
|
11
|
-
|
12
|
-
# RSS 2.0 elements that need including
|
13
|
-
element :copyright
|
14
|
-
element :description
|
15
|
-
element :language
|
16
|
-
element :managingEditor
|
17
|
-
element :title
|
18
|
-
element :link, :as => :url
|
19
|
-
|
20
|
-
# If author is not present use managingEditor on the channel
|
21
|
-
element :"itunes:author", :as => :itunes_author
|
22
|
-
element :"itunes:block", :as => :itunes_block
|
23
|
-
element :"itunes:image", :value => :href, :as => :itunes_image
|
24
|
-
element :"itunes:explicit", :as => :itunes_explicit
|
25
|
-
element :"itunes:keywords", :as => :itunes_keywords
|
26
|
-
# New URL for the podcast feed
|
27
|
-
element :"itunes:new-feed-url", :as => :itunes_new_feed_url
|
28
|
-
element :"itunes:subtitle", :as => :itunes_subtitle
|
29
|
-
# If summary is not present, use the description tag
|
30
|
-
element :"itunes:summary", :as => :itunes_summary
|
31
|
-
|
32
|
-
# iTunes RSS feeds can have multiple main categories...
|
33
|
-
# ...and multiple sub-categories per category
|
34
|
-
# TODO subcategories not supported correctly - they are at the same level
|
35
|
-
# as the main categories
|
36
|
-
elements :"itunes:category", :as => :itunes_categories, :value => :text
|
37
|
-
|
38
|
-
elements :"itunes:owner", :as => :itunes_owners, :class => ITunesRSSOwner
|
39
|
-
|
40
|
-
elements :item, :as => :entries, :class => ITunesRSSItem
|
41
|
-
|
42
|
-
def self.able_to_parse?(xml)
|
43
|
-
xml =~ /xmlns:itunes=\"http:\/\/www.itunes.com\/dtds\/podcast-1.0.dtd\"/
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# iTunes extensions to the standard RSS2.0 item
|
5
|
-
# Source: http://www.apple.com/itunes/whatson/podcasts/specs.html
|
6
|
-
class ITunesRSSItem
|
7
|
-
include SAXMachine
|
8
|
-
include FeedUtilities
|
9
|
-
element :author
|
10
|
-
element :guid
|
11
|
-
element :title
|
12
|
-
element :link, :as => :url
|
13
|
-
element :description, :as => :summary
|
14
|
-
element :pubDate, :as => :published
|
15
|
-
|
16
|
-
# If author is not present use author tag on the item
|
17
|
-
element :"itunes:author", :as => :itunes_author
|
18
|
-
element :"itunes:block", :as => :itunes_block
|
19
|
-
element :"itunes:duration", :as => :itunes_duration
|
20
|
-
element :"itunes:explicit", :as => :itunes_explicit
|
21
|
-
element :"itunes:keywords", :as => :itunes_keywords
|
22
|
-
element :"itunes:subtitle", :as => :itunes_subtitle
|
23
|
-
# If summary is not present, use the description tag
|
24
|
-
element :"itunes:summary", :as => :itunes_summary
|
25
|
-
element :enclosure, :value => :length, :as => :enclosure_length
|
26
|
-
element :enclosure, :value => :type, :as => :enclosure_type
|
27
|
-
element :enclosure, :value => :url, :as => :enclosure_url
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
-
|
3
|
-
describe Feedzirra::Parser::ITunesRSSItem do
|
4
|
-
before(:each) do
|
5
|
-
# I don't really like doing it this way because these unit test should only rely on ITunesRssItem,
|
6
|
-
# but this is actually how it should work. You would never just pass entry xml straight to the ITunesRssItem
|
7
|
-
@item = Feedzirra::Parser::ITunesRSS.parse(sample_itunes_feed).entries.first
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should parse the title" do
|
11
|
-
@item.title.should == "Shake Shake Shake Your Spices"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should parse the author" do
|
15
|
-
@item.itunes_author.should == "John Doe"
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should parse the subtitle" do
|
19
|
-
@item.itunes_subtitle.should == "A short primer on table spices"
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should parse the summary" do
|
23
|
-
@item.itunes_summary.should == "This week we talk about salt and pepper shakers, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!"
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should parse the enclosure" do
|
27
|
-
@item.enclosure_length.should == "8727310"
|
28
|
-
@item.enclosure_type.should == "audio/x-m4a"
|
29
|
-
@item.enclosure_url.should == "http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a"
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should parse the guid" do
|
33
|
-
@item.guid.should == "http://example.com/podcasts/archive/aae20050615.m4a"
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should parse the published date" do
|
37
|
-
@item.published.should == "Wed, 15 Jun 2005 19:00:00 GMT"
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should parse the duration" do
|
41
|
-
@item.itunes_duration.should == "7:04"
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should parse the keywords" do
|
45
|
-
@item.itunes_keywords.should == "salt, pepper, shaker, exciting"
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
-
|
3
|
-
describe Feedzirra::Parser::ITunesRSSOwner do
|
4
|
-
before(:each) do
|
5
|
-
# I don't really like doing it this way because these unit test should only rely on RSSEntry,
|
6
|
-
# but this is actually how it should work. You would never just pass entry xml straight to the ITunesRssOwner
|
7
|
-
@owner = Feedzirra::Parser::ITunesRSS.parse(sample_itunes_feed).itunes_owners.first
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should parse the name" do
|
11
|
-
@owner.name.should == "John Doe"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should parse the email" do
|
15
|
-
@owner.email.should == "john.doe@example.com"
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
-
|
3
|
-
describe Feedzirra::Parser::ITunesRSS do
|
4
|
-
describe "#will_parse?" do
|
5
|
-
it "should return true for an itunes RSS feed" do
|
6
|
-
Feedzirra::Parser::ITunesRSS.should be_able_to_parse(sample_itunes_feed)
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should return fase for an atom feed" do
|
10
|
-
Feedzirra::Parser::ITunesRSS.should_not be_able_to_parse(sample_atom_feed)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "parsing" do
|
15
|
-
before(:each) do
|
16
|
-
@feed = Feedzirra::Parser::ITunesRSS.parse(sample_itunes_feed)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should parse the subtitle" do
|
20
|
-
@feed.itunes_subtitle.should == "A show about everything"
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should parse the author" do
|
24
|
-
@feed.itunes_author.should == "John Doe"
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should parse an owner" do
|
28
|
-
@feed.itunes_owners.size.should == 1
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should parse an image" do
|
32
|
-
@feed.itunes_image.should == "http://example.com/podcasts/everything/AllAboutEverything.jpg"
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should parse categories" do
|
36
|
-
@feed.itunes_categories.size == 3
|
37
|
-
@feed.itunes_categories[0] == "Technology"
|
38
|
-
@feed.itunes_categories[1] == "Gadgets"
|
39
|
-
@feed.itunes_categories[2] == "TV & Film"
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should parse the summary" do
|
43
|
-
@feed.itunes_summary.should == "All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store"
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should parse entries" do
|
47
|
-
@feed.entries.size.should == 3
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|