jsl-myzofeedtosis 0.0.1.2 → 0.0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +103 -71
- data/lib/myzofeedtosis.rb +3 -1
- data/lib/myzofeedtosis/client.rb +37 -30
- data/lib/myzofeedtosis/result.rb +43 -0
- data/myzofeedtosis.gemspec +13 -6
- data/spec/myzofeedtosis/client_spec.rb +13 -5
- data/spec/myzofeedtosis/result_spec.rb +30 -0
- metadata +4 -1
data/README.rdoc
CHANGED
@@ -1,108 +1,140 @@
|
|
1
1
|
= Description
|
2
2
|
|
3
|
-
Myzofeedtosis is a library that helps you to efficiently process syndicated web
|
4
|
-
|
3
|
+
Myzofeedtosis is a library that helps you to efficiently process syndicated web
|
4
|
+
resources. It helps by automatically using conditional HTTP GET requests, as
|
5
|
+
well as by pointing out which entries are new in any given feed.
|
5
6
|
|
6
7
|
== Name
|
7
8
|
|
8
|
-
The name "myzofeedtosis" is based on the form of cellular digestion
|
9
|
-
|
10
|
-
|
9
|
+
The name "myzofeedtosis" is based on the form of cellular digestion
|
10
|
+
"myzocytosis". According to Wikipedia [1], myzocytosis is described as the
|
11
|
+
process where "one cell pierces another using a feeding tube, and sucks out
|
12
|
+
cytoplasm". Myzofeedtosis is kind of like that, except it works with RSS/Atom
|
13
|
+
feeds instead of cytoplasm.
|
11
14
|
|
12
15
|
1 - http://en.wikipedia.org/wiki/List_of_vores
|
13
16
|
|
14
17
|
== Philosophy
|
15
18
|
|
16
|
-
Myzofeedtosis is designed to help you with book-keeping about feed fetching
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
Myzofeedtosis is designed to help you with book-keeping about feed fetching
|
20
|
+
details. This is usually something that is mundane and not fundamentally related
|
21
|
+
to the business logic of applications that deal with the consumption of
|
22
|
+
syndicated content on the web. Myzofeedtosis keeps track of these mundane
|
23
|
+
details so you can just keep grabbing new content without wasting bandwidth in
|
24
|
+
making unnecessary requests and programmer time in implementing algorithms to
|
25
|
+
figure out which feed entries are new.
|
26
|
+
|
27
|
+
Myzofeedtosis fits into other frameworks to do the heavy lifting, including the
|
28
|
+
Curb library which does HTTP requests through curl, and FeedNormalizer which
|
29
|
+
abstracts the differences between syndication formats. In the sense that it fits
|
30
|
+
into these existing, robust programs, Myzofeedtosis is a modular middleware
|
31
|
+
piece that efficiently glues together disparate parts to create a helpful feed
|
32
|
+
reader with a minimal (< 200 LOC), test-covered codebase.
|
26
33
|
|
27
34
|
== Installation
|
28
35
|
|
29
|
-
Assuming that you've followed the directions on gems.github.com to allow your
|
30
|
-
following command will install the
|
36
|
+
Assuming that you've followed the directions on gems.github.com to allow your
|
37
|
+
computer to install gems from GitHub, the following command will install the
|
38
|
+
Myzofeedtosis library:
|
31
39
|
|
32
|
-
|
40
|
+
sudo gem install jsl-myzofeedtosis
|
33
41
|
|
34
42
|
== Usage
|
35
43
|
|
36
|
-
Myzofeedtosis is easy to use.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
44
|
+
Myzofeedtosis is easy to use. Just create a client object, and invoke the
|
45
|
+
"fetch" method:
|
46
|
+
|
47
|
+
require 'myzofeedtosis'
|
48
|
+
client = Myzofeedtosis::Client.new('http://feeds.feedburner.com/wooster')
|
49
|
+
result = client.fetch
|
50
|
+
|
51
|
+
+result+ will be a Myzofeedtosis::Result object which delegates methods to
|
52
|
+
the FeedNormalizer::Feed object as well as the Curl::Easy object used to fetch
|
53
|
+
the feed. Useful methods on this object include +entries+, +new_entries+ and
|
54
|
+
+response_code+ among many others (basically all of the methods that
|
55
|
+
FeedNormalizer::Feed and Curl::Easy objects respond to should be implemented).
|
56
|
+
|
57
|
+
Note that since Myzofeedtosis uses HTTP conditional GET, it may not actually
|
58
|
+
have received a full XML response from the server suitable for being parsed
|
59
|
+
into entries. In this case, methods such as +entries+ on the Myzofeedtosis::Result
|
60
|
+
will return +nil+. Depending on your application logic, you may want to inspect
|
61
|
+
the methods that are delegated to the Curl::Easy object, such as +response_code+,
|
62
|
+
for more information on what happened in these cases.
|
63
|
+
|
64
|
+
On subsequent requests of a particular resource, Myzofeedtosis will update
|
65
|
+
+new_entries+ to contain the feed entries that we haven't seen yet. In most
|
66
|
+
applications, your program will probably call the same batch of URLS multiple
|
67
|
+
times, and process the elements in +new_entries+.
|
68
|
+
|
69
|
+
You will most likely want to allow Myzofeedtosis to remember details about the
|
70
|
+
last retrieval of a feed after the client is removed from memory. Myzofeedtosis
|
71
|
+
uses Moneta, a unified interface to key-value storage systems to remember
|
72
|
+
"summaries" of feeds that it has seen in the past. See the document section on
|
73
|
+
Customization for more details on how to configure this system.
|
57
74
|
|
58
75
|
== Customization
|
59
76
|
|
60
|
-
Myzofeedtosis stores summaries of feeds in a key-value storage system.
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
Myzofeedtosis stores summaries of feeds in a key-value storage system. If no
|
78
|
+
options are included when creating a new Myzofeedtosis::Client object, the
|
79
|
+
default is to use a "memory" storage system. The memory system is just a basic
|
80
|
+
ruby Hash, so it won't keep track of feeds after a particular Client is removed
|
81
|
+
from memory. To configure a different backend, pass an options hash to the
|
82
|
+
Myzofeedtosis client initialization:
|
64
83
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
This example sets up a Memcache backend, which in this case points to Tokyo Tyrant on port 1978. Note that Moneta::Memcache
|
70
|
-
can be given as a string, in which case you don't have to manually require Moneta::Memcache before initializing the client.
|
84
|
+
url = "http://newsrss.bbc.co.uk/rss/newsonline_world_edition/south_asia/rss.xml"
|
85
|
+
mf = Myzofeedtosis::Client.new(url, :backend => {:moneta_klass => 'Moneta::Memcache', :server => 'localhost:1978'})
|
86
|
+
res = mf.fetch
|
71
87
|
|
72
|
-
|
73
|
-
|
88
|
+
This example sets up a Memcache backend, which in this case points to Tokyo
|
89
|
+
Tyrant on port 1978. Note that Moneta::Memcache can be given as a string, in
|
90
|
+
which case you don't have to manually require Moneta::Memcache before
|
91
|
+
initializing the client.
|
74
92
|
|
75
|
-
|
93
|
+
Generally, Myzofeedtosis supports all systems supported by Moneta, and any one
|
94
|
+
of the supported systems can be given to the +moneta_klass+ parameter. Other
|
95
|
+
options following +backend+ are passed directly to Moneta for configuration.
|
76
96
|
|
77
|
-
|
78
|
-
order to accomplish this without having to require that the user store information such as etags and dates of the last retrieved entry,
|
79
|
-
Myzofeedtosis stores a summary structure in the configured key-value store (backed by Moneta). In order to do conditional GET
|
80
|
-
requests, Myzofeedtosis stores the Last-Modified date, as well as the ETag of the last request in the summary structure, which is
|
81
|
-
put in a namespaced element consisting of the term 'Myzofeedtosis' (bet you won't have to worry about name collisions on that one!)
|
82
|
-
and the MD5 of the URL retrieved.
|
97
|
+
== Implementation
|
83
98
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
of
|
88
|
-
|
99
|
+
Myzofeedtosis helps to identify new feed entries and to figure out when
|
100
|
+
conditional GET can be used in retrieving resources. In order to accomplish this
|
101
|
+
without having to require that the user store information such as etags and
|
102
|
+
dates of the last retrieved entry, Myzofeedtosis stores a summary structure in
|
103
|
+
the configured key-value store (backed by Moneta). In order to do conditional
|
104
|
+
GET requests, Myzofeedtosis stores the Last-Modified date, as well as the ETag
|
105
|
+
of the last request in the summary structure, which is put in a namespaced
|
106
|
+
element consisting of the term 'Myzofeedtosis' (bet you won't have to worry
|
107
|
+
about name collisions on that one!) and the MD5 of the URL retrieved.
|
108
|
+
|
109
|
+
It can also be a bit tricky to decipher which feed entries are new since many
|
110
|
+
feed sources don't include unique ids with their feeds. Myzofeedtosis reliably
|
111
|
+
keeps track of which entries in a feed are new by storing (in the summary hash
|
112
|
+
mentioned above) an MD5 signature of each entry in a feed. It takes elements
|
113
|
+
such as the published-at date, title and content and generates the MD5 of these
|
114
|
+
elements. This allows Myzofeedtosis to cheaply compute (both in terms of
|
115
|
+
computation and storage) which feed entries should be presented to the user as
|
116
|
+
"new". Below is an example of a summary structure:
|
89
117
|
|
90
118
|
{
|
91
|
-
:etag=>"4c8f-46ac09fbbe940",
|
92
|
-
:
|
119
|
+
:etag => "4c8f-46ac09fbbe940",
|
120
|
+
:last_modified => "Mon, 25 May 2009 18:17:33 GMT",
|
121
|
+
:digests => ["f2993783ded928637ce5f2dc2d837f10", "da64efa6dd9ce34e5699b9efe73a37a7"]
|
93
122
|
}
|
94
|
-
|
95
|
-
The data stored by Myzofeedtosis in the summary structure allows it to be
|
96
|
-
data that are unnecessary for
|
123
|
+
|
124
|
+
The data stored by Myzofeedtosis in the summary structure allows it to be
|
125
|
+
helpful to the user without storing lots of data that are unnecessary for
|
126
|
+
efficient functioning.
|
97
127
|
|
98
128
|
== HTML cleaning/sanitizing
|
99
129
|
|
100
|
-
Myzofeedtosis doesn't do anything about feed sanitizing, as other libraries have
|
101
|
-
|
130
|
+
Myzofeedtosis doesn't do anything about feed sanitizing, as other libraries have
|
131
|
+
been built for this purpose. FeedNormalizer has methods for escaping entries,
|
132
|
+
but to strip HTML I suggest that you look at the Ruby gem "sanitize".
|
102
133
|
|
103
134
|
== Feedback
|
104
135
|
|
105
|
-
Please let me know if you have any problems with or questions about
|
136
|
+
Please let me know if you have any problems with or questions about
|
137
|
+
Myzofeedtosis.
|
106
138
|
|
107
139
|
= Author
|
108
140
|
|
data/lib/myzofeedtosis.rb
CHANGED
data/lib/myzofeedtosis/client.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module Myzofeedtosis
|
2
2
|
|
3
|
-
# Myzofeedtosis::Client is the primary interface to the feed reader. Call it
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
3
|
+
# Myzofeedtosis::Client is the primary interface to the feed reader. Call it
|
4
|
+
# with a url that was previously fetched while connected to the configured
|
5
|
+
# backend, and it will 1) only do a retrieval if deemed necessary based on the
|
6
|
+
# etag and modified-at of the last etag and 2) mark all entries retrieved as
|
7
|
+
# either new or not new. Entries retrieved are normalized using the
|
8
|
+
# feed-normalizer gem.
|
7
9
|
class Client
|
8
10
|
attr_reader :options, :url
|
9
11
|
|
@@ -22,22 +24,25 @@ module Myzofeedtosis
|
|
22
24
|
@options[:backend].except(:moneta_klass) )
|
23
25
|
end
|
24
26
|
|
25
|
-
# Retrieves the latest entries from this feed. Returns a
|
26
|
-
# method +new_entries+ if the response was
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
27
|
+
# Retrieves the latest entries from this feed. Returns a
|
28
|
+
# Feednormalizer::Feed object with method +new_entries+ if the response was
|
29
|
+
# successful, otherwise returns the Curl::Easy object that we used to
|
30
|
+
# retrieve this resource. Note that we also return this object if the
|
31
|
+
# request resulted in a 304 (Not Modified) response code since we don't have
|
32
|
+
# any new results. Depending on your business logic, you may want to do
|
33
|
+
# something in this case, such as putting this resource in a lower-priority
|
34
|
+
# queue if it is not frequently updated.
|
31
35
|
def fetch
|
32
36
|
curl = build_curl_easy
|
33
37
|
curl.perform
|
34
|
-
process_curl_response(curl)
|
38
|
+
feed = process_curl_response(curl)
|
39
|
+
Myzofeedtosis::Result.new(curl, feed)
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
38
43
|
|
39
|
-
# Marks entries as either seen or not seen based on the unique signature of
|
40
|
-
# is calculated by taking the MD5 of common attributes.
|
44
|
+
# Marks entries as either seen or not seen based on the unique signature of
|
45
|
+
# the entry, which is calculated by taking the MD5 of common attributes.
|
41
46
|
def mark_new_entries(response)
|
42
47
|
digests = if summary_for_feed.nil? || summary_for_feed[:digests].nil?
|
43
48
|
[ ]
|
@@ -45,8 +50,8 @@ module Myzofeedtosis
|
|
45
50
|
summary_for_feed[:digests]
|
46
51
|
end
|
47
52
|
|
48
|
-
# For each entry in the responses object, mark @_seen as false if the
|
49
|
-
# doesn't exist in the cached object.
|
53
|
+
# For each entry in the responses object, mark @_seen as false if the
|
54
|
+
# digest of this entry doesn't exist in the cached object.
|
50
55
|
response.entries.each do |e|
|
51
56
|
seen = digests.include?(digest_for(e))
|
52
57
|
e.instance_variable_set(:@_seen, seen)
|
@@ -63,17 +68,16 @@ module Myzofeedtosis
|
|
63
68
|
response = mark_new_entries(response)
|
64
69
|
store_summary_to_backend(response, curl)
|
65
70
|
response
|
66
|
-
else
|
67
|
-
curl
|
68
71
|
end
|
69
72
|
end
|
70
73
|
|
71
|
-
# Sets options for the Curl::Easy object, including parameters for HTTP
|
74
|
+
# Sets options for the Curl::Easy object, including parameters for HTTP
|
75
|
+
# conditional GET.
|
72
76
|
def build_curl_easy
|
73
77
|
curl = new_curl_easy(url)
|
74
78
|
|
75
|
-
# Many feeds have a 302 redirect to another URL. For more recent versions
|
76
|
-
# we need to specify this.
|
79
|
+
# Many feeds have a 302 redirect to another URL. For more recent versions
|
80
|
+
# of Curl, we need to specify this.
|
77
81
|
curl.follow_location = true
|
78
82
|
|
79
83
|
set_header_options(curl)
|
@@ -93,8 +97,8 @@ module Myzofeedtosis
|
|
93
97
|
summary = summary_for_feed
|
94
98
|
|
95
99
|
unless summary.nil?
|
96
|
-
# We should only try to populate the headers for a conditional GET if
|
97
|
-
# of these values.
|
100
|
+
# We should only try to populate the headers for a conditional GET if
|
101
|
+
# we know both of these values.
|
98
102
|
if summary[:etag] && summary[:last_modified]
|
99
103
|
curl.headers['If-None-Match'] = summary[:etag]
|
100
104
|
curl.headers['If-Modified-Since'] = summary[:last_modified]
|
@@ -108,9 +112,10 @@ module Myzofeedtosis
|
|
108
112
|
MD5.hexdigest(@url)
|
109
113
|
end
|
110
114
|
|
111
|
-
# Stores information about the retrieval, including ETag, Last-Modified,
|
112
|
-
# entries to the backend store. This enables
|
113
|
-
# marking of entries as
|
115
|
+
# Stores information about the retrieval, including ETag, Last-Modified,
|
116
|
+
# and MD5 digests of all entries to the backend store. This enables
|
117
|
+
# conditional GET usage on subsequent requests and marking of entries as
|
118
|
+
# either new or seen.
|
114
119
|
def store_summary_to_backend(feed, curl)
|
115
120
|
headers = HttpHeaders.new(curl.header_str)
|
116
121
|
|
@@ -120,7 +125,8 @@ module Myzofeedtosis
|
|
120
125
|
summary.merge!(:etag => headers.etag) unless headers.etag.nil?
|
121
126
|
summary.merge!(:last_modified => headers.last_modified) unless headers.last_modified.nil?
|
122
127
|
|
123
|
-
# Store digest for each feed entry so we can detect new feeds on the next
|
128
|
+
# Store digest for each feed entry so we can detect new feeds on the next
|
129
|
+
# retrieval
|
124
130
|
digests = feed.entries.map do |e|
|
125
131
|
digest_for(e)
|
126
132
|
end
|
@@ -133,11 +139,12 @@ module Myzofeedtosis
|
|
133
139
|
@backend[key_for_cached] = summary
|
134
140
|
end
|
135
141
|
|
136
|
-
# Computes a unique signature for the FeedNormalizer::Entry object given.
|
137
|
-
# will be the MD5 of enough fields to have a reasonable
|
138
|
-
# entry is unique or not.
|
142
|
+
# Computes a unique signature for the FeedNormalizer::Entry object given.
|
143
|
+
# This signature will be the MD5 of enough fields to have a reasonable
|
144
|
+
# probability of determining if the entry is unique or not.
|
139
145
|
def digest_for(entry)
|
140
|
-
MD5.hexdigest([entry.date_published, entry.url, entry.title,
|
146
|
+
MD5.hexdigest( [ entry.date_published, entry.url, entry.title,
|
147
|
+
entry.content ].join)
|
141
148
|
end
|
142
149
|
|
143
150
|
def parser_for_xml(xml)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Myzofeedtosis
|
2
|
+
|
3
|
+
# Makes the response components both from the Curl::Easy object and the
|
4
|
+
# FeedNormalizer::Feed object available to the user by delegating appropriate
|
5
|
+
# method calls to the correct object. If FeedNormalizer wasn't able to process
|
6
|
+
# the response, calls which would be delegated to this object return nil. In
|
7
|
+
# these cases, depending on your business logic you may want to inspect the
|
8
|
+
# state of the Curl::Easy object.
|
9
|
+
class Result
|
10
|
+
|
11
|
+
# Methods which should be delegated to the FeedNormalizer::Feed object.
|
12
|
+
FEED_METHODS = [ :title, :description, :last_updated, :copyright, :authors,
|
13
|
+
:author, :urls, :url, :image, :generator, :items, :entries, :new_items,
|
14
|
+
:new_entries, :channel, :ttl, :skip_hours, :skip_days
|
15
|
+
] unless defined?(FEED_METHODS)
|
16
|
+
|
17
|
+
def initialize(curl, feed)
|
18
|
+
@curl = curl
|
19
|
+
@feed = feed
|
20
|
+
|
21
|
+
raise ArgumentError, "Curl object must not be nil" if curl.nil?
|
22
|
+
|
23
|
+
# See what the Curl::Easy object responds to, and send any appropriate
|
24
|
+
# messages its way.
|
25
|
+
@curl.public_methods(false).each do |meth|
|
26
|
+
(class << self; self; end).class_eval do
|
27
|
+
define_method meth do |*args|
|
28
|
+
@curl.send(meth, *args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Send methods through to the feed object unless it is nil. If feed
|
35
|
+
# object is nil, return nil in response to method call.
|
36
|
+
FEED_METHODS.each do |meth|
|
37
|
+
define_method meth do |*args|
|
38
|
+
@feed.nil? ? nil : @feed.__send__(meth, *args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/myzofeedtosis.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{myzofeedtosis}
|
3
|
-
s.version = "0.0.1.
|
3
|
+
s.version = "0.0.1.4"
|
4
4
|
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
6
|
s.authors = ["Justin Leitgeb"]
|
@@ -9,10 +9,16 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = %q{justin@phq.org}
|
10
10
|
|
11
11
|
s.files = ["lib/extensions/core/array.rb", "lib/extensions/core/hash.rb",
|
12
|
-
"lib/extensions/feed_normalizer/feed_instance_methods.rb",
|
13
|
-
"
|
14
|
-
"
|
15
|
-
"
|
12
|
+
"lib/extensions/feed_normalizer/feed_instance_methods.rb",
|
13
|
+
"lib/myzofeedtosis/result.rb",
|
14
|
+
"lib/myzofeedtosis/client.rb", "lib/myzofeedtosis.rb", "LICENSE",
|
15
|
+
"myzofeedtosis.gemspec", "Rakefile", "README.rdoc",
|
16
|
+
"spec/extensions/feed_normalizer/feed_instance_methods_spec.rb",
|
17
|
+
"spec/fixtures/http_headers/wooster.txt",
|
18
|
+
"spec/fixtures/xml/older_wooster.xml", "spec/fixtures/xml/wooster.xml",
|
19
|
+
"spec/myzofeedtosis/client_spec.rb", "spec/myzofeedtosis_spec.rb",
|
20
|
+
"spec/myzofeedtosis/result_spec.rb",
|
21
|
+
"spec/spec_helper.rb"]
|
16
22
|
|
17
23
|
s.has_rdoc = true
|
18
24
|
s.homepage = %q{http://github.com/jsl/myzofeedtosis}
|
@@ -20,7 +26,8 @@ Gem::Specification.new do |s|
|
|
20
26
|
s.require_paths = ["lib"]
|
21
27
|
s.rubygems_version = %q{1.3.1}
|
22
28
|
s.summary = %q{Retrieves feeds using conditional GET and marks entries that you haven't seen before}
|
23
|
-
s.test_files = ["spec/myzofeedtosis_spec.rb", "spec/spec_helper.rb", "spec/myzofeedtosis/client_spec.rb"
|
29
|
+
s.test_files = ["spec/myzofeedtosis_spec.rb", "spec/spec_helper.rb", "spec/myzofeedtosis/client_spec.rb",
|
30
|
+
"spec/myzofeedtosis/result_spec.rb" ]
|
24
31
|
|
25
32
|
s.extra_rdoc_files = [ "README.rdoc" ]
|
26
33
|
|
@@ -2,9 +2,9 @@ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
|
|
2
2
|
|
3
3
|
describe Myzofeedtosis::Client do
|
4
4
|
before do
|
5
|
-
@url
|
5
|
+
@url = "http://www.example.com/feed.rss"
|
6
6
|
@opts = { :user_agent => "My Cool Application" }
|
7
|
-
@fr
|
7
|
+
@fr = Myzofeedtosis::Client.new(@url, @opts)
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "initialization" do
|
@@ -46,10 +46,18 @@ describe Myzofeedtosis::Client do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
describe "when the response code is not 200" do
|
49
|
-
it "should return
|
49
|
+
it "should return nil for feed methods such as #title and #author" do
|
50
50
|
curl = mock('curl', :perform => true, :response_code => 304)
|
51
51
|
@fr.expects(:build_curl_easy).returns(curl)
|
52
|
-
@fr.fetch
|
52
|
+
res = @fr.fetch
|
53
|
+
res.title.should be_nil
|
54
|
+
res.author.should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return a Myzofeedtosis::Result object" do
|
58
|
+
curl = mock('curl', :perform => true, :response_code => 304)
|
59
|
+
@fr.expects(:build_curl_easy).returns(curl)
|
60
|
+
@fr.fetch.should be_a(Myzofeedtosis::Result)
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
@@ -59,7 +67,7 @@ describe Myzofeedtosis::Client do
|
|
59
67
|
curl = mock('curl', :perform => true, :response_code => 200,
|
60
68
|
:body_str => xml_fixture('wooster'), :header_str => http_header('wooster'))
|
61
69
|
@fr.expects(:build_curl_easy).returns(curl)
|
62
|
-
@fr.fetch
|
70
|
+
@fr.fetch
|
63
71
|
end
|
64
72
|
|
65
73
|
it "should have an empty array for new_entries" do
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. spec_helper])
|
2
|
+
|
3
|
+
describe Myzofeedtosis::Result do
|
4
|
+
before do
|
5
|
+
@c = mock('curl')
|
6
|
+
@f = mock('feed')
|
7
|
+
@r = Myzofeedtosis::Result.new(@c, @f)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should raise an ArgumentError if the Curl object is nil" do
|
11
|
+
lambda {
|
12
|
+
Myzofeedtosis::Result.new(nil, nil)
|
13
|
+
}.should raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should send author to the Feed object" do
|
17
|
+
@f.expects(:author)
|
18
|
+
@r.author
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should send body_str to the curl object" do
|
22
|
+
@c.expects(:body_str)
|
23
|
+
@r.body_str
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return nil for author if the Feed is nil" do
|
27
|
+
r = Myzofeedtosis::Result.new(@c, nil)
|
28
|
+
r.author
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsl-myzofeedtosis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.
|
4
|
+
version: 0.0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Leitgeb
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/extensions/core/array.rb
|
75
75
|
- lib/extensions/core/hash.rb
|
76
76
|
- lib/extensions/feed_normalizer/feed_instance_methods.rb
|
77
|
+
- lib/myzofeedtosis/result.rb
|
77
78
|
- lib/myzofeedtosis/client.rb
|
78
79
|
- lib/myzofeedtosis.rb
|
79
80
|
- LICENSE
|
@@ -86,6 +87,7 @@ files:
|
|
86
87
|
- spec/fixtures/xml/wooster.xml
|
87
88
|
- spec/myzofeedtosis/client_spec.rb
|
88
89
|
- spec/myzofeedtosis_spec.rb
|
90
|
+
- spec/myzofeedtosis/result_spec.rb
|
89
91
|
- spec/spec_helper.rb
|
90
92
|
has_rdoc: true
|
91
93
|
homepage: http://github.com/jsl/myzofeedtosis
|
@@ -123,3 +125,4 @@ test_files:
|
|
123
125
|
- spec/myzofeedtosis_spec.rb
|
124
126
|
- spec/spec_helper.rb
|
125
127
|
- spec/myzofeedtosis/client_spec.rb
|
128
|
+
- spec/myzofeedtosis/result_spec.rb
|