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 CHANGED
@@ -1,108 +1,140 @@
1
1
  = Description
2
2
 
3
- Myzofeedtosis is a library that helps you to efficiently process syndicated web resources. It helps by automatically using
4
- conditional HTTP GET requests, as well as by pointing out which entries are new in any given feed.
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 "myzocytosis". According to Wikipedia [1], myzocytosis
9
- is described as the process where "one cell pierces another using a feeding tube, and sucks out cytoplasm". Myzofeedtosis is
10
- kind of like that, except it works with RSS/Atom feeds instead of cytoplasm.
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 details. This is usually something that is
17
- mundane and not fundamentally related to the business logic of applications that deal with the consumption of syndicated
18
- content on the web. Myzofeedtosis keeps track of these mundane details so you can just keep grabbing new content without
19
- wasting bandwidth in making unnecessary requests and programmer time in implementing algorithms to figure out which feed
20
- entries are new.
21
-
22
- Myzofeedtosis fits into other frameworks to do the heavy lifting, including the Curb library which does HTTP requests through
23
- curl, and FeedNormalizer which abstracts the differences between syndication formats. In the sense that it fits into these
24
- existing, robust programs, Myzofeedtosis is a modular middleware piece that efficiently glues together disparate parts to create
25
- a helpful feed reader with a minimal (< 200 LOC), test-covered codebase.
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 computer to install gems from GitHub, the
30
- following command will install the Myzofeedtosis library:
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
- sudo gem install jsl-myzofeedtosis
40
+ sudo gem install jsl-myzofeedtosis
33
41
 
34
42
  == Usage
35
43
 
36
- Myzofeedtosis is easy to use. Just create a client object, and invoke the "fetch" method:
37
-
38
- require 'myzofeedtosis'
39
- client = Myzofeedtosis::Client.new('http://feeds.feedburner.com/wooster')
40
- result = client.fetch
41
-
42
- +result+ will be a FeedNormalizer::Feed object, which responds to the method +entries+. In this first case, Myzofeedtosis
43
- isn't much more useful than just using FeedNormalizer by itself. On subsequent requests, though, it helps significantly.
44
- Invoke client.fetch again. Instead of getting back an object that responds to +entries+, you'll probably get back a Curl::Easy
45
- object with a response code of 304, indicating that the resource hasn't changed since the last retrieval. If you invoke
46
- fetch again, assuming one entry was added, you would get back another FeedNormalizer::Feed object. You'll also notice that
47
- all of the FeedNormalizer::Feed objects respond not only to +entries+, but +new_entries+, which is a selection of the entries
48
- that haven't been seen before.
49
-
50
- Myzofeedtosis is designed for these situations where you have one or maybe thousands of feeds that you have to update on a
51
- regular basis. If the results that you receive respond to the method new_entries, iterate over the new entries, processing them
52
- according to your business logic.
53
-
54
- You will most likely want to allow Myzofeedtosis to remember details about the last retrieval of a feed after the client is
55
- removed from memory. Myzofeedtosis uses Moneta, a unified interface to key-value storage systems to remember "summaries" of
56
- feeds that it has seen in the past. See the document section on Customization for more details on how to configure this system.
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. If no options are included when creating a new
61
- Myzofeedtosis::Client object, the default is to use a "memory" storage system. The memory system is just a basic ruby Hash, so it
62
- won't keep track of feeds after a particular Client is removed from memory. To configure a different backend, pass an options hash
63
- to the Myzofeedtosis client initialization:
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
- url = "http://newsrss.bbc.co.uk/rss/newsonline_world_edition/south_asia/rss.xml"
66
- mf = Myzofeedtosis::Client.new(url, :backend => {:moneta_klass => 'Moneta::Memcache', :server => 'localhost:1978'})
67
- res = mf.fetch
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
- Generally, Myzofeedtosis supports all systems supported by Moneta, and any one of the supported systems can be given to the
73
- +moneta_klass+ parameter. Other options following +backend+ are passed directly to Moneta for configuration.
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
- == Implementation
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
- Myzofeedtosis helps to identify new feed entries and to figure out when conditional GET can be used in retrieving resources. In
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
- It can also be a bit tricky to decipher which feed entries are new since many feed sources don't include unique ids with their
85
- feeds. Myzofeedtosis reliably keeps track of which entries in a feed are new by storing (in the summary hash mentioned above) an
86
- MD5 signature of each entry in a feed. It takes elements such as the published-at date, title and content and generates the MD5
87
- of these elements. This allows Myzofeedtosis to cheaply compute (both in terms of computation and storage) which feed entries
88
- should be presented to the user as "new". Below is an example of a summary structure:
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", :last_modified=>"Mon, 25 May 2009 18:17:33 GMT",
92
- :digests=>["f2993783ded928637ce5f2dc2d837f10", "da64efa6dd9ce34e5699b9efe73a37a7"]
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 helpful to the user without storing lots of
96
- data that are unnecessary for efficient functioning.
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 been built for this purpose. FeedNormalizer
101
- has methods for escaping entries, but to strip HTML I suggest that you look at the Ruby gem "sanitize".
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 Myzofeedtosis.
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
@@ -10,5 +10,7 @@ lib_dirs = [ 'extensions', 'myzofeedtosis' ].map do |d|
10
10
  end
11
11
 
12
12
  lib_dirs.each do |d|
13
- Dir[File.join(d, "**", "*.rb")].each {|file| require file }
13
+ Dir[File.join(d, "**", "*.rb")].each do |file|
14
+ require file
15
+ end
14
16
  end
@@ -1,9 +1,11 @@
1
1
  module Myzofeedtosis
2
2
 
3
- # Myzofeedtosis::Client is the primary interface to the feed reader. Call it with a url that was previously fetched while
4
- # connected to the configured backend, and it will 1) only do a retrieval if deemed necessary based on the etag and modified-at
5
- # of the last etag and 2) mark all entries retrieved as either new or not new. Entries retrieved are normalized using
6
- # the feed-normalizer gem.
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 Feednormalizer::Feed object with
26
- # method +new_entries+ if the response was successful, otherwise returns the Curl::Easy object
27
- # that we used to retrieve this resource. Note that we also return this object if the request
28
- # resulted in a 304 (Not Modified) response code since we don't have any new results. Depending
29
- # on your business logic, you may want to do something in this case, such as putting this
30
- # resource in a lower-priority queue if it is not frequently updated.
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 the entry, which
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 digest of this entry
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 conditional GET.
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 of Curl,
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 we know both
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, and MD5 digests of all
112
- # entries to the backend store. This enables conditional GET usage on subsequent requests and
113
- # marking of entries as either new or seen.
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 retrieval
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. This signature
137
- # will be the MD5 of enough fields to have a reasonable probability of determining if the
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, entry.content].join)
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{myzofeedtosis}
3
- s.version = "0.0.1.2"
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", "lib/myzofeedtosis/client.rb", "lib/myzofeedtosis.rb",
13
- "LICENSE", "myzofeedtosis.gemspec", "Rakefile", "README.rdoc", "spec/extensions/feed_normalizer/feed_instance_methods_spec.rb",
14
- "spec/fixtures/http_headers/wooster.txt", "spec/fixtures/xml/older_wooster.xml", "spec/fixtures/xml/wooster.xml",
15
- "spec/myzofeedtosis/client_spec.rb", "spec/myzofeedtosis_spec.rb", "spec/spec_helper.rb"]
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 = "http://www.example.com/feed.rss"
5
+ @url = "http://www.example.com/feed.rss"
6
6
  @opts = { :user_agent => "My Cool Application" }
7
- @fr = Myzofeedtosis::Client.new(@url, @opts)
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 the Curl::Easy object" do
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.should == curl
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.2
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