jsl-myzofeedtosis 0.0.1.2 → 0.0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|