feedzirra 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +0 -14
- data/README.md +2 -241
- data/feedzirra.gemspec +2 -8
- data/lib/feedzirra.rb +2 -15
- data/lib/feedzirra/version.rb +1 -1
- metadata +7 -182
- data/.rspec +0 -1
- data/.travis.yml +0 -8
- data/Guardfile +0 -5
- data/Rakefile +0 -6
- data/benchmarks/README.md +0 -90
- data/benchmarks/basic.rb +0 -31
- data/benchmarks/feed_list.txt +0 -10
- data/benchmarks/feed_xml/apple.xml +0 -149
- data/benchmarks/feed_xml/cnn.xml +0 -278
- data/benchmarks/feed_xml/daring_fireball.xml +0 -1697
- data/benchmarks/feed_xml/engadget.xml +0 -604
- data/benchmarks/feed_xml/feedzirra_commits.xml +0 -370
- data/benchmarks/feed_xml/gizmodo.xml +0 -2
- data/benchmarks/feed_xml/loop.xml +0 -441
- data/benchmarks/feed_xml/rails.xml +0 -1938
- data/benchmarks/feed_xml/white_house.xml +0 -951
- data/benchmarks/feed_xml/xkcd.xml +0 -2
- data/benchmarks/fetching_systems.rb +0 -23
- data/benchmarks/other_libraries.rb +0 -73
- data/lib/feedzirra/core_ext.rb +0 -3
- data/lib/feedzirra/core_ext/date.rb +0 -19
- data/lib/feedzirra/core_ext/string.rb +0 -9
- data/lib/feedzirra/core_ext/time.rb +0 -31
- data/lib/feedzirra/feed.rb +0 -459
- data/lib/feedzirra/feed_entry_utilities.rb +0 -66
- data/lib/feedzirra/feed_utilities.rb +0 -103
- data/lib/feedzirra/parser.rb +0 -20
- data/lib/feedzirra/parser/atom.rb +0 -61
- data/lib/feedzirra/parser/atom_entry.rb +0 -34
- data/lib/feedzirra/parser/atom_feed_burner.rb +0 -22
- data/lib/feedzirra/parser/atom_feed_burner_entry.rb +0 -35
- data/lib/feedzirra/parser/google_docs_atom.rb +0 -28
- data/lib/feedzirra/parser/google_docs_atom_entry.rb +0 -29
- data/lib/feedzirra/parser/itunes_rss.rb +0 -50
- data/lib/feedzirra/parser/itunes_rss_item.rb +0 -41
- data/lib/feedzirra/parser/itunes_rss_owner.rb +0 -12
- data/lib/feedzirra/parser/rss.rb +0 -24
- data/lib/feedzirra/parser/rss_entry.rb +0 -37
- data/lib/feedzirra/parser/rss_feed_burner.rb +0 -23
- data/lib/feedzirra/parser/rss_feed_burner_entry.rb +0 -43
- data/spec/feedzirra/feed_entry_utilities_spec.rb +0 -62
- data/spec/feedzirra/feed_spec.rb +0 -762
- data/spec/feedzirra/feed_utilities_spec.rb +0 -273
- data/spec/feedzirra/parser/atom_entry_spec.rb +0 -86
- data/spec/feedzirra/parser/atom_feed_burner_entry_spec.rb +0 -47
- data/spec/feedzirra/parser/atom_feed_burner_spec.rb +0 -56
- data/spec/feedzirra/parser/atom_spec.rb +0 -76
- data/spec/feedzirra/parser/google_docs_atom_entry_spec.rb +0 -22
- data/spec/feedzirra/parser/google_docs_atom_spec.rb +0 -31
- data/spec/feedzirra/parser/itunes_rss_item_spec.rb +0 -63
- data/spec/feedzirra/parser/itunes_rss_owner_spec.rb +0 -18
- data/spec/feedzirra/parser/itunes_rss_spec.rb +0 -58
- data/spec/feedzirra/parser/rss_entry_spec.rb +0 -85
- data/spec/feedzirra/parser/rss_feed_burner_entry_spec.rb +0 -85
- data/spec/feedzirra/parser/rss_feed_burner_spec.rb +0 -57
- data/spec/feedzirra/parser/rss_spec.rb +0 -57
- data/spec/sample_feeds/AmazonWebServicesBlog.xml +0 -797
- data/spec/sample_feeds/AmazonWebServicesBlogFirstEntryContent.xml +0 -63
- data/spec/sample_feeds/AtomFeedWithSpacesAroundEquals.xml +0 -61
- data/spec/sample_feeds/FeedBurnerUrlNoAlternate.xml +0 -28
- data/spec/sample_feeds/GoogleDocsList.xml +0 -188
- data/spec/sample_feeds/HREFConsideredHarmful.xml +0 -314
- data/spec/sample_feeds/HREFConsideredHarmfulFirstEntry.xml +0 -22
- data/spec/sample_feeds/ITunesWithSpacesInAttributes.xml +0 -63
- data/spec/sample_feeds/PaulDixExplainsNothing.xml +0 -175
- data/spec/sample_feeds/PaulDixExplainsNothingAlternate.xml +0 -175
- data/spec/sample_feeds/PaulDixExplainsNothingFirstEntryContent.xml +0 -19
- data/spec/sample_feeds/PaulDixExplainsNothingWFW.xml +0 -174
- data/spec/sample_feeds/SamRuby.xml +0 -583
- data/spec/sample_feeds/TechCrunch.xml +0 -1515
- data/spec/sample_feeds/TechCrunchFirstEntry.xml +0 -9
- data/spec/sample_feeds/TechCrunchFirstEntryDescription.xml +0 -3
- data/spec/sample_feeds/TenderLovemaking.xml +0 -516
- data/spec/sample_feeds/TenderLovemakingFirstEntry.xml +0 -66
- data/spec/sample_feeds/TrotterCashionHome.xml +0 -611
- data/spec/sample_feeds/TypePadNews.xml +0 -368
- data/spec/sample_feeds/atom_with_link_tag_for_url_unmarked.xml +0 -31
- data/spec/sample_feeds/itunes.xml +0 -67
- data/spec/sample_feeds/pet_atom.xml +0 -497
- data/spec/spec_helper.rb +0 -88
@@ -1,41 +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 FeedEntryUtilities
|
9
|
-
|
10
|
-
element :author
|
11
|
-
element :guid, :as => :entry_id
|
12
|
-
element :title
|
13
|
-
element :link, :as => :url
|
14
|
-
element :description, :as => :summary
|
15
|
-
element :"content:encoded", :as => :content
|
16
|
-
element :pubDate, :as => :published
|
17
|
-
|
18
|
-
# If author is not present use author tag on the item
|
19
|
-
element :"itunes:author", :as => :itunes_author
|
20
|
-
element :"itunes:block", :as => :itunes_block
|
21
|
-
element :"itunes:duration", :as => :itunes_duration
|
22
|
-
element :"itunes:explicit", :as => :itunes_explicit
|
23
|
-
element :"itunes:keywords", :as => :itunes_keywords
|
24
|
-
element :"itunes:subtitle", :as => :itunes_subtitle
|
25
|
-
element :"itunes:image", :value => :href, :as => :itunes_image
|
26
|
-
element :"itunes:isClosedCaptioned", :as => :itunes_closed_captioned
|
27
|
-
element :"itunes:order", :as => :itunes_order
|
28
|
-
# If summary is not present, use the description tag
|
29
|
-
element :"itunes:summary", :as => :itunes_summary
|
30
|
-
element :enclosure, :value => :length, :as => :enclosure_length
|
31
|
-
element :enclosure, :value => :type, :as => :enclosure_type
|
32
|
-
element :enclosure, :value => :url, :as => :enclosure_url
|
33
|
-
|
34
|
-
def guid
|
35
|
-
warn "Feedzirra: ITunesRSSItem.guid is deprecated, please use `id` or `entry_id` instead. This will be removed in version 1.0"
|
36
|
-
id
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
data/lib/feedzirra/parser/rss.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# Parser for dealing with RSS feeds.
|
5
|
-
class RSS
|
6
|
-
include SAXMachine
|
7
|
-
include FeedUtilities
|
8
|
-
element :rss, as: :version, value: :version
|
9
|
-
element :title
|
10
|
-
element :description
|
11
|
-
element :link, :as => :url
|
12
|
-
elements :item, :as => :entries, :class => RSSEntry
|
13
|
-
|
14
|
-
attr_accessor :feed_url
|
15
|
-
attr_accessor :hubs
|
16
|
-
|
17
|
-
def self.able_to_parse?(xml) #:nodoc:
|
18
|
-
(/\<rss|\<rdf/ =~ xml) && !(/feedburner/ =~ xml)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# Parser for dealing with RDF feed entries.
|
5
|
-
class RSSEntry
|
6
|
-
include SAXMachine
|
7
|
-
include FeedEntryUtilities
|
8
|
-
|
9
|
-
element :title
|
10
|
-
element :link, :as => :url
|
11
|
-
|
12
|
-
element :"dc:creator", :as => :author
|
13
|
-
element :author, :as => :author
|
14
|
-
element :"content:encoded", :as => :content
|
15
|
-
element :description, :as => :summary
|
16
|
-
|
17
|
-
element :"media:content", :as => :image, :value => :url
|
18
|
-
element :enclosure, :as => :image, :value => :url
|
19
|
-
|
20
|
-
element :pubDate, :as => :published
|
21
|
-
element :pubdate, :as => :published
|
22
|
-
element :"dc:date", :as => :published
|
23
|
-
element :"dc:Date", :as => :published
|
24
|
-
element :"dcterms:created", :as => :published
|
25
|
-
|
26
|
-
|
27
|
-
element :"dcterms:modified", :as => :updated
|
28
|
-
element :issued, :as => :published
|
29
|
-
elements :category, :as => :categories
|
30
|
-
|
31
|
-
element :guid, :as => :entry_id
|
32
|
-
element :"dc:identifier", :as => :entry_id
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# Parser for dealing with RSS feeds.
|
5
|
-
class RSSFeedBurner
|
6
|
-
include SAXMachine
|
7
|
-
include FeedUtilities
|
8
|
-
element :title
|
9
|
-
element :description
|
10
|
-
element :link, :as => :url
|
11
|
-
elements :"atom10:link", :as => :hubs, :value => :href, :with => {:rel => "hub"}
|
12
|
-
elements :item, :as => :entries, :class => RSSFeedBurnerEntry
|
13
|
-
|
14
|
-
attr_accessor :feed_url
|
15
|
-
|
16
|
-
def self.able_to_parse?(xml) #:nodoc:
|
17
|
-
(/\<rss|\<rdf/ =~ xml) && (/feedburner/ =~ xml)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Feedzirra
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
# Parser for dealing with RDF feed entries.
|
5
|
-
class RSSFeedBurnerEntry
|
6
|
-
include SAXMachine
|
7
|
-
include FeedEntryUtilities
|
8
|
-
|
9
|
-
element :title
|
10
|
-
|
11
|
-
element :"feedburner:origLink", :as => :url
|
12
|
-
element :link, :as => :url
|
13
|
-
|
14
|
-
element :"dc:creator", :as => :author
|
15
|
-
element :author, :as => :author
|
16
|
-
element :"content:encoded", :as => :content
|
17
|
-
element :description, :as => :summary
|
18
|
-
|
19
|
-
element :"media:content", :as => :image, :value => :url
|
20
|
-
element :enclosure, :as => :image, :value => :url
|
21
|
-
|
22
|
-
element :pubDate, :as => :published
|
23
|
-
element :pubdate, :as => :published
|
24
|
-
element :"dc:date", :as => :published
|
25
|
-
element :"dc:Date", :as => :published
|
26
|
-
element :"dcterms:created", :as => :published
|
27
|
-
|
28
|
-
|
29
|
-
element :"dcterms:modified", :as => :updated
|
30
|
-
element :issued, :as => :published
|
31
|
-
elements :category, :as => :categories
|
32
|
-
|
33
|
-
element :guid, :as => :entry_id
|
34
|
-
|
35
|
-
def url
|
36
|
-
@url || @link
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Feedzirra::FeedUtilities do
|
4
|
-
before(:each) do
|
5
|
-
@klass = Class.new do
|
6
|
-
include Feedzirra::FeedEntryUtilities
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe "handling dates" do
|
11
|
-
it "should parse an ISO 8601 formatted datetime into Time" do
|
12
|
-
time = @klass.new.parse_datetime("2008-02-20T8:05:00-010:00")
|
13
|
-
time.class.should == Time
|
14
|
-
time.should == Time.parse_safely("Wed Feb 20 18:05:00 UTC 2008")
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should parse a ISO 8601 with milliseconds into Time" do
|
18
|
-
time = @klass.new.parse_datetime("2013-09-17T08:20:13.931-04:00")
|
19
|
-
time.class.should == Time
|
20
|
-
time.should == Time.parse_safely("Tue Sep 17 12:20:13 UTC 2013")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "sanitizing" do
|
25
|
-
before(:each) do
|
26
|
-
@feed = Feedzirra::Feed.parse(sample_atom_feed)
|
27
|
-
@entry = @feed.entries.first
|
28
|
-
end
|
29
|
-
|
30
|
-
it "doesn't fail when no elements are defined on includer" do
|
31
|
-
expect { @klass.new.sanitize! }.to_not raise_error
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should provide a sanitized title" do
|
35
|
-
new_title = "<script>this is not safe</script>" + @entry.title
|
36
|
-
@entry.title = new_title
|
37
|
-
@entry.title.sanitize.should == Loofah.scrub_fragment(new_title, :prune).to_s
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should sanitize content in place" do
|
41
|
-
new_content = "<script>" + @entry.content
|
42
|
-
@entry.content = new_content.dup
|
43
|
-
@entry.content.sanitize!.should == Loofah.scrub_fragment(new_content, :prune).to_s
|
44
|
-
@entry.content.should == Loofah.scrub_fragment(new_content, :prune).to_s
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should sanitize things in place" do
|
48
|
-
@entry.title += "<script>"
|
49
|
-
@entry.author += "<script>"
|
50
|
-
@entry.content += "<script>"
|
51
|
-
|
52
|
-
cleaned_title = Loofah.scrub_fragment(@entry.title, :prune).to_s
|
53
|
-
cleaned_author = Loofah.scrub_fragment(@entry.author, :prune).to_s
|
54
|
-
cleaned_content = Loofah.scrub_fragment(@entry.content, :prune).to_s
|
55
|
-
|
56
|
-
@entry.sanitize!
|
57
|
-
@entry.title.should == cleaned_title
|
58
|
-
@entry.author.should == cleaned_author
|
59
|
-
@entry.content.should == cleaned_content
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/spec/feedzirra/feed_spec.rb
DELETED
@@ -1,762 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
|
3
|
-
class Hell < StandardError; end
|
4
|
-
|
5
|
-
class FailParser
|
6
|
-
def self.parse(_, &on_failure)
|
7
|
-
on_failure.call 'this parser always fails.'
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe Feedzirra::Feed do
|
12
|
-
|
13
|
-
describe "#add_common_feed_element" do
|
14
|
-
before(:all) do
|
15
|
-
Feedzirra::Feed.add_common_feed_element("generator")
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should parse the added element out of Atom feeds" do
|
19
|
-
Feedzirra::Feed.parse(sample_wfw_feed).generator.should == "TypePad"
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should parse the added element out of Atom Feedburner feeds" do
|
23
|
-
Feedzirra::Parser::Atom.new.should respond_to(:generator)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should parse the added element out of RSS feeds" do
|
27
|
-
Feedzirra::Parser::RSS.new.should respond_to(:generator)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "#add_common_feed_entry_element" do
|
32
|
-
before(:all) do
|
33
|
-
Feedzirra::Feed.add_common_feed_entry_element("wfw:commentRss", :as => :comment_rss)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should parse the added element out of Atom feeds entries" do
|
37
|
-
Feedzirra::Feed.parse(sample_wfw_feed).entries.first.comment_rss.should == "this is the new val"
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should parse the added element out of Atom Feedburner feeds entries" do
|
41
|
-
Feedzirra::Parser::AtomEntry.new.should respond_to(:comment_rss)
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should parse the added element out of RSS feeds entries" do
|
45
|
-
Feedzirra::Parser::RSSEntry.new.should respond_to(:comment_rss)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe '#parse_with' do
|
50
|
-
let(:xml) { '<xml></xml>' }
|
51
|
-
|
52
|
-
it 'invokes the parser and passes the xml' do
|
53
|
-
parser = double 'Parser', parse: nil
|
54
|
-
parser.should_receive(:parse).with xml
|
55
|
-
Feedzirra::Feed.parse_with parser, xml
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'with a callback block' do
|
59
|
-
it 'passes the callback to the parser' do
|
60
|
-
callback = ->(*) { raise Hell }
|
61
|
-
|
62
|
-
expect do
|
63
|
-
Feedzirra::Feed.parse_with FailParser, xml, &callback
|
64
|
-
end.to raise_error Hell
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe "#parse" do # many of these tests are redundant with the specific feed type tests, but I put them here for completeness
|
70
|
-
context "when there's an available parser" do
|
71
|
-
it "should parse an rdf feed" do
|
72
|
-
feed = Feedzirra::Feed.parse(sample_rdf_feed)
|
73
|
-
feed.title.should == "HREF Considered Harmful"
|
74
|
-
feed.entries.first.published.should == Time.parse_safely("Tue Sep 02 19:50:07 UTC 2008")
|
75
|
-
feed.entries.size.should == 10
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should parse an rss feed" do
|
79
|
-
feed = Feedzirra::Feed.parse(sample_rss_feed)
|
80
|
-
feed.title.should == "Tender Lovemaking"
|
81
|
-
feed.entries.first.published.should == Time.parse_safely("Thu Dec 04 17:17:49 UTC 2008")
|
82
|
-
feed.entries.size.should == 10
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should parse an atom feed" do
|
86
|
-
feed = Feedzirra::Feed.parse(sample_atom_feed)
|
87
|
-
feed.title.should == "Amazon Web Services Blog"
|
88
|
-
feed.entries.first.published.should == Time.parse_safely("Fri Jan 16 18:21:00 UTC 2009")
|
89
|
-
feed.entries.size.should == 10
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should parse an feedburner atom feed" do
|
93
|
-
feed = Feedzirra::Feed.parse(sample_feedburner_atom_feed)
|
94
|
-
feed.title.should == "Paul Dix Explains Nothing"
|
95
|
-
feed.entries.first.published.should == Time.parse_safely("Thu Jan 22 15:50:22 UTC 2009")
|
96
|
-
feed.entries.size.should == 5
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should parse an itunes feed" do
|
100
|
-
feed = Feedzirra::Feed.parse(sample_itunes_feed)
|
101
|
-
feed.title.should == "All About Everything"
|
102
|
-
feed.entries.first.published.should == Time.parse_safely("Wed, 15 Jun 2005 19:00:00 GMT")
|
103
|
-
feed.entries.size.should == 3
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context "when there's no available parser" do
|
108
|
-
it "raises Feedzirra::NoParserAvailable" do
|
109
|
-
proc {
|
110
|
-
Feedzirra::Feed.parse("I'm an invalid feed")
|
111
|
-
}.should raise_error(Feedzirra::NoParserAvailable)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
it "should parse an feedburner rss feed" do
|
116
|
-
feed = Feedzirra::Feed.parse(sample_rss_feed_burner_feed)
|
117
|
-
feed.title.should == "TechCrunch"
|
118
|
-
feed.entries.first.published.should == Time.parse_safely("Wed Nov 02 17:25:27 UTC 2011")
|
119
|
-
feed.entries.size.should == 20
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "#determine_feed_parser_for_xml" do
|
124
|
-
it 'should return the Feedzirra::Parser::GoogleDocsAtom calss for a Google Docs atom feed' do
|
125
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_google_docs_list_feed).should == Feedzirra::Parser::GoogleDocsAtom
|
126
|
-
end
|
127
|
-
|
128
|
-
it "should return the Feedzirra::Parser::Atom class for an atom feed" do
|
129
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_atom_feed).should == Feedzirra::Parser::Atom
|
130
|
-
end
|
131
|
-
|
132
|
-
it "should return the Feedzirra::Parser::AtomFeedBurner class for an atom feedburner feed" do
|
133
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_feedburner_atom_feed).should == Feedzirra::Parser::AtomFeedBurner
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should return the Feedzirra::Parser::RSS class for an rdf/rss 1.0 feed" do
|
137
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_rdf_feed).should == Feedzirra::Parser::RSS
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should return the Feedzirra::Parser::RSSFeedBurner class for an rss feedburner feed" do
|
141
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_rss_feed_burner_feed).should == Feedzirra::Parser::RSSFeedBurner
|
142
|
-
end
|
143
|
-
|
144
|
-
it "should return the Feedzirra::Parser::RSS object for an rss 2.0 feed" do
|
145
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_rss_feed).should == Feedzirra::Parser::RSS
|
146
|
-
end
|
147
|
-
|
148
|
-
it "should return a Feedzirra::Parser::RSS object for an itunes feed" do
|
149
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(sample_itunes_feed).should == Feedzirra::Parser::ITunesRSS
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
describe "#setup_easy" do
|
155
|
-
class MockCurl
|
156
|
-
attr_accessor :follow_location, :userpwd, :proxy_url, :proxy_port, :max_redirects, :timeout, :ssl_verify_host, :ssl_verify_peer, :ssl_version, :enable_cookies, :cookiefile, :cookies
|
157
|
-
|
158
|
-
def headers
|
159
|
-
@headers ||= {}
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
let(:curl) { MockCurl.new }
|
164
|
-
|
165
|
-
it "sets defaults on curl" do
|
166
|
-
Feedzirra::Feed.setup_easy curl
|
167
|
-
|
168
|
-
curl.headers["User-Agent"].should eq Feedzirra::Feed::USER_AGENT
|
169
|
-
curl.follow_location.should eq true
|
170
|
-
end
|
171
|
-
|
172
|
-
it "allows user agent over-ride" do
|
173
|
-
Feedzirra::Feed.setup_easy(curl, user_agent: '007')
|
174
|
-
curl.headers["User-Agent"].should eq '007'
|
175
|
-
end
|
176
|
-
|
177
|
-
it "enables compression" do
|
178
|
-
Feedzirra::Feed.setup_easy(curl, compress: true)
|
179
|
-
curl.headers["Accept-encoding"].should eq 'gzip, deflate'
|
180
|
-
end
|
181
|
-
|
182
|
-
it "enables compression even when you act like you don't want it" do
|
183
|
-
Feedzirra::Feed.setup_easy(curl, compress: false)
|
184
|
-
curl.headers["Accept-encoding"].should eq 'gzip, deflate'
|
185
|
-
end
|
186
|
-
|
187
|
-
it "sets up http auth" do
|
188
|
-
Feedzirra::Feed.setup_easy(curl, http_authentication: ['user', 'pass'])
|
189
|
-
curl.userpwd.should eq 'user:pass'
|
190
|
-
end
|
191
|
-
|
192
|
-
it "passes known options to curl" do
|
193
|
-
known_options = {
|
194
|
-
enable_cookies: true,
|
195
|
-
cookiefile: 'cookies.txt',
|
196
|
-
cookies: 'asdf',
|
197
|
-
proxy_url: 'http://proxy.url.com',
|
198
|
-
proxy_port: '1234',
|
199
|
-
max_redirects: 2,
|
200
|
-
timeout: 500,
|
201
|
-
ssl_verify_host: true,
|
202
|
-
ssl_verify_peer: true,
|
203
|
-
ssl_version: :omg
|
204
|
-
}
|
205
|
-
|
206
|
-
Feedzirra::Feed.setup_easy curl, known_options
|
207
|
-
|
208
|
-
known_options.each do |option|
|
209
|
-
key, value = option
|
210
|
-
curl.send(key).should eq value
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
it "ignores unknown options" do
|
215
|
-
expect { Feedzirra::Feed.setup_easy curl, foo: :bar }.to_not raise_error
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
describe "when adding feed types" do
|
220
|
-
it "should prioritize added types over the built in ones" do
|
221
|
-
feed_text = "Atom asdf"
|
222
|
-
Feedzirra::Parser::Atom.stub(:able_to_parse?).and_return(true)
|
223
|
-
new_feed_type = Class.new do
|
224
|
-
def self.able_to_parse?(val)
|
225
|
-
true
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
new_feed_type.should be_able_to_parse(feed_text)
|
230
|
-
Feedzirra::Feed.add_feed_class(new_feed_type)
|
231
|
-
Feedzirra::Feed.determine_feed_parser_for_xml(feed_text).should == new_feed_type
|
232
|
-
|
233
|
-
# this is a hack so that this doesn't break the rest of the tests
|
234
|
-
Feedzirra::Feed.feed_classes.reject! {|o| o == new_feed_type }
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
describe '#etag_from_header' do
|
239
|
-
before(:each) do
|
240
|
-
@header = "HTTP/1.0 200 OK\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\nETag: ziEyTl4q9GH04BR4jgkImd0GvSE\r\nP3P: CP=\"ALL DSP COR NID CUR OUR NOR\"\r\nConnection: close\r\nContent-Type: text/xml;charset=utf-8\r\n\r\n"
|
241
|
-
end
|
242
|
-
|
243
|
-
it "should return the etag from the header if it exists" do
|
244
|
-
Feedzirra::Feed.etag_from_header(@header).should == "ziEyTl4q9GH04BR4jgkImd0GvSE"
|
245
|
-
end
|
246
|
-
|
247
|
-
it "should return nil if there is no etag in the header" do
|
248
|
-
Feedzirra::Feed.etag_from_header("foo").should be_nil
|
249
|
-
end
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
describe '#last_modified_from_header' do
|
254
|
-
before(:each) do
|
255
|
-
@header = "HTTP/1.0 200 OK\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\nETag: ziEyTl4q9GH04BR4jgkImd0GvSE\r\nP3P: CP=\"ALL DSP COR NID CUR OUR NOR\"\r\nConnection: close\r\nContent-Type: text/xml;charset=utf-8\r\n\r\n"
|
256
|
-
end
|
257
|
-
|
258
|
-
it "should return the last modified date from the header if it exists" do
|
259
|
-
Feedzirra::Feed.last_modified_from_header(@header).should == Time.parse_safely("Wed, 28 Jan 2009 04:10:32 GMT")
|
260
|
-
end
|
261
|
-
|
262
|
-
it "should return nil if there is no last modified date in the header" do
|
263
|
-
Feedzirra::Feed.last_modified_from_header("foo").should be_nil
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
describe "fetching feeds" do
|
268
|
-
before(:each) do
|
269
|
-
@paul_feed = { :xml => load_sample("PaulDixExplainsNothing.xml"), :url => "http://feeds.feedburner.com/PaulDixExplainsNothing" }
|
270
|
-
@trotter_feed = { :xml => load_sample("TrotterCashionHome.xml"), :url => "http://feeds2.feedburner.com/trottercashion" }
|
271
|
-
@invalid_feed = { :xml => 'This feed is invalid', :url => "http://feeds.feedburner.com/InvalidFeed" }
|
272
|
-
end
|
273
|
-
|
274
|
-
describe "#fetch_raw" do
|
275
|
-
before(:each) do
|
276
|
-
@cmock = double('cmock', :header_str => '', :body_str => @paul_feed[:xml] )
|
277
|
-
@multi = double('curl_multi', :add => true, :perform => true)
|
278
|
-
@curl_easy = double('curl_easy')
|
279
|
-
@curl = double('curl', :headers => {}, :follow_location= => true, :on_failure => true, :on_complete => true)
|
280
|
-
@curl.stub(:on_success).and_yield(@cmock)
|
281
|
-
|
282
|
-
Curl::Multi.stub(:new).and_return(@multi)
|
283
|
-
Curl::Easy.stub(:new).and_yield(@curl).and_return(@curl_easy)
|
284
|
-
end
|
285
|
-
|
286
|
-
it "should set user agent if it's passed as an option" do
|
287
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :user_agent => 'Custom Useragent')
|
288
|
-
@curl.headers['User-Agent'].should == 'Custom Useragent'
|
289
|
-
end
|
290
|
-
|
291
|
-
it "should set user agent to default if it's not passed as an option" do
|
292
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url])
|
293
|
-
@curl.headers['User-Agent'].should == Feedzirra::Feed::USER_AGENT
|
294
|
-
end
|
295
|
-
|
296
|
-
it "should set if modified since as an option if passed" do
|
297
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_modified_since => Time.parse_safely("Wed, 28 Jan 2009 04:10:32 GMT"))
|
298
|
-
@curl.headers["If-Modified-Since"].should == 'Wed, 28 Jan 2009 04:10:32 GMT'
|
299
|
-
end
|
300
|
-
|
301
|
-
it "should set if none match as an option if passed" do
|
302
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
|
303
|
-
@curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
304
|
-
end
|
305
|
-
|
306
|
-
it 'should set userpwd for http basic authentication if :http_authentication is passed' do
|
307
|
-
@curl.should_receive(:userpwd=).with('username:password')
|
308
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :http_authentication => ['username', 'password'])
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'should set accepted encodings' do
|
312
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url], :compress => true)
|
313
|
-
@curl.headers["Accept-encoding"].should == 'gzip, deflate'
|
314
|
-
end
|
315
|
-
|
316
|
-
it "should return raw xml" do
|
317
|
-
Feedzirra::Feed.fetch_raw(@paul_feed[:url]).should =~ /^#{Regexp.escape('<?xml version="1.0" encoding="UTF-8"?>')}/
|
318
|
-
end
|
319
|
-
|
320
|
-
it "should take multiple feed urls and return a hash of urls and response xml" do
|
321
|
-
multi = double('curl_multi', :add => true, :perform => true)
|
322
|
-
Curl::Multi.stub(:new).and_return(multi)
|
323
|
-
|
324
|
-
paul_response = double('paul_response', :header_str => '', :body_str => @paul_feed[:xml] )
|
325
|
-
trotter_response = double('trotter_response', :header_str => '', :body_str => @trotter_feed[:xml] )
|
326
|
-
|
327
|
-
paul_curl = double('paul_curl', :headers => {}, :follow_location= => true, :on_failure => true, :on_complete => true)
|
328
|
-
paul_curl.stub(:on_success).and_yield(paul_response)
|
329
|
-
|
330
|
-
trotter_curl = double('trotter_curl', :headers => {}, :follow_location= => true, :on_failure => true, :on_complete => true)
|
331
|
-
trotter_curl.stub(:on_success).and_yield(trotter_response)
|
332
|
-
|
333
|
-
Curl::Easy.should_receive(:new).with(@paul_feed[:url]).ordered.and_yield(paul_curl)
|
334
|
-
Curl::Easy.should_receive(:new).with(@trotter_feed[:url]).ordered.and_yield(trotter_curl)
|
335
|
-
|
336
|
-
results = Feedzirra::Feed.fetch_raw([@paul_feed[:url], @trotter_feed[:url]])
|
337
|
-
results.keys.should include(@paul_feed[:url])
|
338
|
-
results.keys.should include(@trotter_feed[:url])
|
339
|
-
results[@paul_feed[:url]].should =~ /Paul Dix/
|
340
|
-
results[@trotter_feed[:url]].should =~ /Trotter Cashion/
|
341
|
-
end
|
342
|
-
|
343
|
-
it "should always return a hash when passed an array" do
|
344
|
-
results = Feedzirra::Feed.fetch_raw([@paul_feed[:url]])
|
345
|
-
results.class.should == Hash
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
describe "#add_url_to_multi" do
|
350
|
-
before(:each) do
|
351
|
-
allow_message_expectations_on_nil
|
352
|
-
@multi = Curl::Multi.get([@paul_feed[:url]], {:follow_location => true}, {:pipeline => true})
|
353
|
-
@multi.stub(:add)
|
354
|
-
@easy_curl = Curl::Easy.new(@paul_feed[:url])
|
355
|
-
|
356
|
-
Curl::Easy.should_receive(:new).and_yield(@easy_curl)
|
357
|
-
end
|
358
|
-
|
359
|
-
it "should set user agent if it's passed as an option" do
|
360
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :user_agent => 'My cool application')
|
361
|
-
@easy_curl.headers["User-Agent"].should == 'My cool application'
|
362
|
-
end
|
363
|
-
|
364
|
-
it "should set user agent to default if it's not passed as an option" do
|
365
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
366
|
-
@easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
|
367
|
-
end
|
368
|
-
|
369
|
-
it "should set if modified since as an option if passed" do
|
370
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_modified_since => Time.parse_safely("Jan 25 2009 04:10:32 GMT"))
|
371
|
-
@easy_curl.headers["If-Modified-Since"].should == 'Sun, 25 Jan 2009 04:10:32 GMT'
|
372
|
-
end
|
373
|
-
|
374
|
-
it 'should set follow location to true' do
|
375
|
-
@easy_curl.should_receive(:follow_location=).with(true)
|
376
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
377
|
-
end
|
378
|
-
|
379
|
-
it 'should set userpwd for http basic authentication if :http_authentication is passed' do
|
380
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :http_authentication => ['myusername', 'mypassword'])
|
381
|
-
@easy_curl.userpwd.should == 'myusername:mypassword'
|
382
|
-
end
|
383
|
-
|
384
|
-
it 'should set accepted encodings' do
|
385
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {:compress => true})
|
386
|
-
@easy_curl.headers["Accept-encoding"].should == 'gzip, deflate'
|
387
|
-
end
|
388
|
-
|
389
|
-
it "should set if_none_match as an option if passed" do
|
390
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
|
391
|
-
@easy_curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
392
|
-
end
|
393
|
-
|
394
|
-
describe 'on success' do
|
395
|
-
before(:each) do
|
396
|
-
@feed = double('feed', :feed_url= => true, :etag= => true, :last_modified= => true)
|
397
|
-
Feedzirra::Feed.stub(:decode_content).and_return(@paul_feed[:xml])
|
398
|
-
Feedzirra::Feed.stub(:determine_feed_parser_for_xml).and_return(Feedzirra::Parser::AtomFeedBurner)
|
399
|
-
Feedzirra::Parser::AtomFeedBurner.stub(:parse).and_return(@feed)
|
400
|
-
Feedzirra::Feed.stub(:etag_from_header).and_return('ziEyTl4q9GH04BR4jgkImd0GvSE')
|
401
|
-
Feedzirra::Feed.stub(:last_modified_from_header).and_return('Wed, 28 Jan 2009 04:10:32 GMT')
|
402
|
-
end
|
403
|
-
|
404
|
-
it 'should decode the response body' do
|
405
|
-
Feedzirra::Feed.should_receive(:decode_content).with(@easy_curl).and_return(@paul_feed[:xml])
|
406
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
407
|
-
@easy_curl.on_success.call(@easy_curl)
|
408
|
-
end
|
409
|
-
|
410
|
-
it 'should determine the xml parser class' do
|
411
|
-
Feedzirra::Feed.should_receive(:determine_feed_parser_for_xml).with(@paul_feed[:xml]).and_return(Feedzirra::Parser::AtomFeedBurner)
|
412
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
413
|
-
@easy_curl.on_success.call(@easy_curl)
|
414
|
-
end
|
415
|
-
|
416
|
-
it 'should parse the xml' do
|
417
|
-
Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).
|
418
|
-
with(@paul_feed[:xml]).and_return(@feed)
|
419
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
420
|
-
@easy_curl.on_success.call(@easy_curl)
|
421
|
-
end
|
422
|
-
|
423
|
-
describe 'when a compatible xml parser class is found' do
|
424
|
-
it 'should set the last effective url to the feed url' do
|
425
|
-
@easy_curl.should_receive(:last_effective_url).and_return(@paul_feed[:url])
|
426
|
-
@feed.should_receive(:feed_url=).with(@paul_feed[:url])
|
427
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
428
|
-
@easy_curl.on_success.call(@easy_curl)
|
429
|
-
end
|
430
|
-
|
431
|
-
it 'should set the etags on the feed' do
|
432
|
-
@feed.should_receive(:etag=).with('ziEyTl4q9GH04BR4jgkImd0GvSE')
|
433
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
434
|
-
@easy_curl.on_success.call(@easy_curl)
|
435
|
-
end
|
436
|
-
|
437
|
-
it 'should set the last modified on the feed' do
|
438
|
-
@feed.should_receive(:last_modified=).with('Wed, 28 Jan 2009 04:10:32 GMT')
|
439
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
|
440
|
-
@easy_curl.on_success.call(@easy_curl)
|
441
|
-
end
|
442
|
-
|
443
|
-
it 'should add the feed to the responses' do
|
444
|
-
responses = {}
|
445
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
|
446
|
-
@easy_curl.on_success.call(@easy_curl)
|
447
|
-
|
448
|
-
responses.length.should == 1
|
449
|
-
responses['http://feeds.feedburner.com/PaulDixExplainsNothing'].should == @feed
|
450
|
-
end
|
451
|
-
|
452
|
-
it 'should call proc if :on_success option is passed' do
|
453
|
-
success = lambda { |url, feed| }
|
454
|
-
success.should_receive(:call).with(@paul_feed[:url], @feed)
|
455
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_success => success })
|
456
|
-
@easy_curl.on_success.call(@easy_curl)
|
457
|
-
end
|
458
|
-
|
459
|
-
describe 'when the parser raises an exception' do
|
460
|
-
it 'invokes the on_failure callback with that exception' do
|
461
|
-
failure = double 'Failure callback', arity: 2
|
462
|
-
failure.should_receive(:call).with(@easy_curl, an_instance_of(Hell))
|
463
|
-
|
464
|
-
Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).and_raise Hell
|
465
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { on_failure: failure })
|
466
|
-
|
467
|
-
@easy_curl.on_success.call(@easy_curl)
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
describe 'when the parser invokes its on_failure callback' do
|
472
|
-
before(:each) do
|
473
|
-
Feedzirra::Feed.stub(:determine_feed_parser_for_xml).and_return FailParser
|
474
|
-
end
|
475
|
-
|
476
|
-
it 'invokes the on_failure callback' do
|
477
|
-
failure = double 'Failure callback', arity: 2
|
478
|
-
failure.should_receive(:call).with(@easy_curl, an_instance_of(RuntimeError))
|
479
|
-
|
480
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { on_failure: failure })
|
481
|
-
@easy_curl.on_success.call(@easy_curl)
|
482
|
-
end
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
describe 'when no compatible xml parser class is found' do
|
487
|
-
it 'invokes the on_failure callback' do
|
488
|
-
failure = double 'Failure callback', arity: 2
|
489
|
-
failure.should_receive(:call).with(@easy_curl, "Can't determine a parser")
|
490
|
-
|
491
|
-
Feedzirra::Feed.should_receive(:determine_feed_parser_for_xml).and_return nil
|
492
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { on_failure: failure })
|
493
|
-
|
494
|
-
@easy_curl.on_success.call(@easy_curl)
|
495
|
-
end
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
describe 'on failure' do
|
500
|
-
before(:each) do
|
501
|
-
@headers = "HTTP/1.0 500 Something Bad\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\n"
|
502
|
-
@body = 'Sorry, something broke'
|
503
|
-
|
504
|
-
@easy_curl.stub(:response_code).and_return(500)
|
505
|
-
@easy_curl.stub(:header_str).and_return(@headers)
|
506
|
-
@easy_curl.stub(:body_str).and_return(@body)
|
507
|
-
end
|
508
|
-
|
509
|
-
it 'should call proc if :on_failure option is passed' do
|
510
|
-
failure = double 'Failure callback', arity: 2
|
511
|
-
failure.should_receive(:call).with(@easy_curl, nil)
|
512
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_failure => failure })
|
513
|
-
@easy_curl.on_failure.call(@easy_curl)
|
514
|
-
end
|
515
|
-
|
516
|
-
it 'should return the http code in the responses' do
|
517
|
-
responses = {}
|
518
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
|
519
|
-
@easy_curl.on_failure.call(@easy_curl)
|
520
|
-
|
521
|
-
responses.length.should == 1
|
522
|
-
responses[@paul_feed[:url]].should == 500
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
describe 'on complete for 404s' do
|
527
|
-
before(:each) do
|
528
|
-
@headers = "HTTP/1.0 404 Not Found\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\n"
|
529
|
-
@body = 'Page could not be found.'
|
530
|
-
|
531
|
-
@easy_curl.stub(:response_code).and_return(404)
|
532
|
-
@easy_curl.stub(:header_str).and_return(@headers)
|
533
|
-
@easy_curl.stub(:body_str).and_return(@body)
|
534
|
-
end
|
535
|
-
|
536
|
-
it 'should call proc if :on_failure option is passed' do
|
537
|
-
complete = double 'Failure callback', arity: 2
|
538
|
-
complete.should_receive(:call).with(@easy_curl, 'Server returned a 404')
|
539
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_failure => complete })
|
540
|
-
@easy_curl.on_missing.call(@easy_curl)
|
541
|
-
end
|
542
|
-
|
543
|
-
it 'should return the http code in the responses' do
|
544
|
-
responses = {}
|
545
|
-
Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
|
546
|
-
@easy_curl.on_complete.call(@easy_curl)
|
547
|
-
|
548
|
-
responses.length.should == 1
|
549
|
-
responses[@paul_feed[:url]].should == 404
|
550
|
-
end
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
describe "#add_feed_to_multi" do
|
555
|
-
before(:each) do
|
556
|
-
allow_message_expectations_on_nil
|
557
|
-
@multi = Curl::Multi.get([@paul_feed[:url]], {:follow_location => true}, {:pipeline => true})
|
558
|
-
@multi.stub(:add)
|
559
|
-
@easy_curl = Curl::Easy.new(@paul_feed[:url])
|
560
|
-
@feed = Feedzirra::Feed.parse(sample_feedburner_atom_feed)
|
561
|
-
|
562
|
-
Curl::Easy.should_receive(:new).and_yield(@easy_curl)
|
563
|
-
end
|
564
|
-
|
565
|
-
it "should set user agent if it's passed as an option" do
|
566
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, :user_agent => 'My cool application')
|
567
|
-
@easy_curl.headers["User-Agent"].should == 'My cool application'
|
568
|
-
end
|
569
|
-
|
570
|
-
it "should set user agent to default if it's not passed as an option" do
|
571
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
572
|
-
@easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
|
573
|
-
end
|
574
|
-
|
575
|
-
it "should set if modified since as an option if passed" do
|
576
|
-
modified_time = Time.parse_safely("Wed, 28 Jan 2009 04:10:32 GMT")
|
577
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {:if_modified_since => modified_time})
|
578
|
-
modified_time.should be > @feed.last_modified
|
579
|
-
|
580
|
-
@easy_curl.headers["If-Modified-Since"].should == modified_time
|
581
|
-
end
|
582
|
-
|
583
|
-
it 'should set follow location to true' do
|
584
|
-
@easy_curl.should_receive(:follow_location=).with(true)
|
585
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
586
|
-
end
|
587
|
-
|
588
|
-
it 'should set userpwd for http basic authentication if :http_authentication is passed' do
|
589
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, :http_authentication => ['myusername', 'mypassword'])
|
590
|
-
@easy_curl.userpwd.should == 'myusername:mypassword'
|
591
|
-
end
|
592
|
-
|
593
|
-
it "should set if_none_match as an option if passed" do
|
594
|
-
@feed.etag = 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
595
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
596
|
-
@easy_curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
|
597
|
-
end
|
598
|
-
|
599
|
-
describe 'on success' do
|
600
|
-
before(:each) do
|
601
|
-
@new_feed = @feed.clone
|
602
|
-
@feed.stub(:update_from_feed)
|
603
|
-
Feedzirra::Feed.stub(:decode_content).and_return(@paul_feed[:xml])
|
604
|
-
Feedzirra::Feed.stub(:determine_feed_parser_for_xml).and_return(Feedzirra::Parser::AtomFeedBurner)
|
605
|
-
Feedzirra::Parser::AtomFeedBurner.stub(:parse).and_return(@new_feed)
|
606
|
-
Feedzirra::Feed.stub(:etag_from_header).and_return('ziEyTl4q9GH04BR4jgkImd0GvSE')
|
607
|
-
Feedzirra::Feed.stub(:last_modified_from_header).and_return('Wed, 28 Jan 2009 04:10:32 GMT')
|
608
|
-
end
|
609
|
-
|
610
|
-
it 'should parse the updated feed' do
|
611
|
-
Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).and_return(@new_feed)
|
612
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
613
|
-
@easy_curl.on_success.call(@easy_curl)
|
614
|
-
end
|
615
|
-
|
616
|
-
it 'should set the last effective url to the feed url' do
|
617
|
-
@easy_curl.should_receive(:last_effective_url).and_return(@paul_feed[:url])
|
618
|
-
@new_feed.should_receive(:feed_url=).with(@paul_feed[:url])
|
619
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
620
|
-
@easy_curl.on_success.call(@easy_curl)
|
621
|
-
end
|
622
|
-
|
623
|
-
it 'should set the etags on the feed' do
|
624
|
-
@new_feed.should_receive(:etag=).with('ziEyTl4q9GH04BR4jgkImd0GvSE')
|
625
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
626
|
-
@easy_curl.on_success.call(@easy_curl)
|
627
|
-
end
|
628
|
-
|
629
|
-
it 'should set the last modified on the feed' do
|
630
|
-
@new_feed.should_receive(:last_modified=).with('Wed, 28 Jan 2009 04:10:32 GMT')
|
631
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
632
|
-
@easy_curl.on_success.call(@easy_curl)
|
633
|
-
end
|
634
|
-
|
635
|
-
it 'should add the feed to the responses' do
|
636
|
-
responses = {}
|
637
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], responses, {})
|
638
|
-
@easy_curl.on_success.call(@easy_curl)
|
639
|
-
|
640
|
-
responses.length.should == 1
|
641
|
-
responses['http://feeds.feedburner.com/PaulDixExplainsNothing'].should == @feed
|
642
|
-
end
|
643
|
-
|
644
|
-
it 'should call proc if :on_success option is passed' do
|
645
|
-
success = lambda { |feed| }
|
646
|
-
success.should_receive(:call).with(@feed)
|
647
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
|
648
|
-
@easy_curl.on_success.call(@easy_curl)
|
649
|
-
end
|
650
|
-
|
651
|
-
it 'should call update from feed on the old feed with the updated feed' do
|
652
|
-
@feed.should_receive(:update_from_feed).with(@new_feed)
|
653
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
|
654
|
-
@easy_curl.on_success.call(@easy_curl)
|
655
|
-
end
|
656
|
-
|
657
|
-
describe 'when the parser invokes its on_failure callback' do
|
658
|
-
before(:each) do
|
659
|
-
Feedzirra::Feed.stub(:determine_feed_parser_for_xml).and_return FailParser
|
660
|
-
end
|
661
|
-
|
662
|
-
it 'invokes the on_failure callback' do
|
663
|
-
failure = double 'Failure callback', arity: 2
|
664
|
-
failure.should_receive(:call)
|
665
|
-
|
666
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { on_failure: failure })
|
667
|
-
@easy_curl.on_success.call(@easy_curl)
|
668
|
-
end
|
669
|
-
end
|
670
|
-
end
|
671
|
-
|
672
|
-
describe 'on failure' do
|
673
|
-
before(:each) do
|
674
|
-
@headers = "HTTP/1.0 404 Not Found\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\n"
|
675
|
-
@body = 'Page could not be found.'
|
676
|
-
|
677
|
-
@easy_curl.stub(:response_code).and_return(404)
|
678
|
-
@easy_curl.stub(:header_str).and_return(@headers)
|
679
|
-
@easy_curl.stub(:body_str).and_return(@body)
|
680
|
-
end
|
681
|
-
|
682
|
-
it 'should call on success callback if the response code is 304' do
|
683
|
-
success = lambda { |feed| }
|
684
|
-
success.should_receive(:call).with(@feed)
|
685
|
-
@easy_curl.should_receive(:response_code).and_return(304)
|
686
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
|
687
|
-
@easy_curl.on_redirect.call(@easy_curl)
|
688
|
-
end
|
689
|
-
|
690
|
-
it 'should return the http code in the responses' do
|
691
|
-
responses = {}
|
692
|
-
Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], responses, {})
|
693
|
-
@easy_curl.on_failure.call(@easy_curl)
|
694
|
-
|
695
|
-
responses.length.should == 1
|
696
|
-
responses[@paul_feed[:url]].should == 404
|
697
|
-
end
|
698
|
-
end
|
699
|
-
end
|
700
|
-
|
701
|
-
describe "#fetch_and_parse" do
|
702
|
-
it "passes options to multicurl" do
|
703
|
-
options = { user_agent: '007' }
|
704
|
-
|
705
|
-
Feedzirra::Feed.should_receive(:add_url_to_multi).
|
706
|
-
with(anything, anything, anything, anything, options)
|
707
|
-
|
708
|
-
Feedzirra::Feed.fetch_and_parse(sample_rss_feed, options)
|
709
|
-
end
|
710
|
-
end
|
711
|
-
|
712
|
-
describe "#decode_content" do
|
713
|
-
before(:each) do
|
714
|
-
@curl_easy = double('curl_easy', :body_str => '<xml></xml>')
|
715
|
-
end
|
716
|
-
|
717
|
-
it 'should decode the response body using gzip if the Content-Encoding: is gzip' do
|
718
|
-
@curl_easy.stub(:header_str).and_return('Content-Encoding: gzip')
|
719
|
-
string_io = double('stringio', :read => @curl_easy.body_str, :close => true)
|
720
|
-
StringIO.should_receive(:new).and_return(string_io)
|
721
|
-
Zlib::GzipReader.should_receive(:new).with(string_io).and_return(string_io)
|
722
|
-
Feedzirra::Feed.decode_content(@curl_easy)
|
723
|
-
end
|
724
|
-
|
725
|
-
it 'should decode the response body using gzip if the Content-Encoding: is gzip even when the case is wrong' do
|
726
|
-
@curl_easy.stub(:header_str).and_return('content-encoding: gzip')
|
727
|
-
string_io = double('stringio', :read => @curl_easy.body_str, :close => true)
|
728
|
-
StringIO.should_receive(:new).and_return(string_io)
|
729
|
-
Zlib::GzipReader.should_receive(:new).with(string_io).and_return(string_io)
|
730
|
-
Feedzirra::Feed.decode_content(@curl_easy)
|
731
|
-
end
|
732
|
-
|
733
|
-
it 'should deflate the response body using inflate if the Content-Encoding: is deflate' do
|
734
|
-
@curl_easy.stub(:header_str).and_return('Content-Encoding: deflate')
|
735
|
-
Zlib::Inflate.should_receive(:inflate).with(@curl_easy.body_str)
|
736
|
-
Feedzirra::Feed.decode_content(@curl_easy)
|
737
|
-
end
|
738
|
-
|
739
|
-
it 'should deflate the response body using inflate if the Content-Encoding: is deflate event if the case is wrong' do
|
740
|
-
@curl_easy.stub(:header_str).and_return('content-encoding: deflate')
|
741
|
-
Zlib::Inflate.should_receive(:inflate).with(@curl_easy.body_str)
|
742
|
-
Feedzirra::Feed.decode_content(@curl_easy)
|
743
|
-
end
|
744
|
-
|
745
|
-
it 'should return the response body if it is not encoded' do
|
746
|
-
@curl_easy.stub(:header_str).and_return('')
|
747
|
-
Feedzirra::Feed.decode_content(@curl_easy).should == '<xml></xml>'
|
748
|
-
end
|
749
|
-
end
|
750
|
-
|
751
|
-
describe "#update" do
|
752
|
-
it "passes options to multicurl" do
|
753
|
-
options = { user_agent: '007' }
|
754
|
-
|
755
|
-
Feedzirra::Feed.should_receive(:add_feed_to_multi).
|
756
|
-
with(anything, anything, anything, anything, options)
|
757
|
-
|
758
|
-
Feedzirra::Feed.update(sample_rss_feed, options)
|
759
|
-
end
|
760
|
-
end
|
761
|
-
end
|
762
|
-
end
|