lib/atom/feed.rb in atom-tools-1.0.0 vs lib/atom/feed.rb in atom-tools-2.0.0

- old
+ new

@@ -19,70 +19,58 @@ # subtitle:: a human-readable description or subtitle (Atom::Text) # updated:: the most recent Time the feed was modified in a way the publisher considers significant # generator:: the agent used to generate a feed # icon:: an IRI identifying an icon which visually identifies a feed (1:1 aspect ratio, looks OK small) # logo:: an IRI identifying an image which visually identifies a feed (2:1 aspect ratio) - # rights:: rights held in and over a feed (Atom::Text) + # rights:: rights held in and over a feed (Atom::Text) # - # There are also +links+, +categories+, +authors+, +contributors+ + # There are also +links+, +categories+, +authors+, +contributors+ # and +entries+, each of which is an Array of its respective type and # can be used thusly: # # entry = feed.entries.new # entry.title = "blah blah blah" + # class Feed < Atom::Element + is_atom_element :feed + attr_reader :uri # the Atom::Feed pointed to by link[@rel='previous'] attr_reader :prev # the Atom::Feed pointed to by link[@rel='next'] attr_reader :next - + # conditional get information from the last fetch attr_reader :etag, :last_modified - element :id, String, true - element :title, Atom::Text, true - element :subtitle, Atom::Text - - element :updated, Atom::Time, true + atom_string :id + atom_element :title, Atom::Title + atom_element :subtitle, Atom::Subtitle - element :links, Atom::Multiple(Atom::Link) - element :categories, Atom::Multiple(Atom::Category) + atom_time :updated - element :authors, Atom::Multiple(Atom::Author) - element :contributors, Atom::Multiple(Atom::Contributor) + include HasLinks + include HasCategories - element :generator, String # XXX with uri and version attributes! - element :icon, String - element :logo, String + atom_elements :author, :authors, Atom::Author + atom_elements :contributor, :contributors, Atom::Contributor - element :rights, Atom::Text - - element :entries, Atom::Multiple(Atom::Entry) + atom_string :generator # XXX with uri and version attributes! + atom_string :icon + atom_string :logo + atom_element :rights, Atom::Rights + + atom_elements :entry, :entries, Atom::Entry + include Enumerable def inspect # :nodoc: "<#{@uri} entries: #{entries.length} title='#{title}'>" end - # parses XML fetched from +base+ into an Atom::Feed - def self.parse xml, base = "" - if xml.respond_to? :to_atom_entry - xml.to_atom_feed(base) - elsif xml.respond_to? :read - self.parse(xml.read) - else - begin - REXML::Document.new(xml.to_s).to_atom_feed(base) - rescue REXML::ParseException - raise Atom::ParseError - end - end - end - # Create a new Feed that can be found at feed_uri and retrieved # using an Atom::HTTP object http def initialize feed_uri = nil, http = Atom::HTTP.new @entries = [] @http = http @@ -90,11 +78,11 @@ if feed_uri @uri = feed_uri.to_uri self.base = feed_uri end - super "feed" + super() end # iterates over a feed's entries def each &block @entries.each &block @@ -106,11 +94,11 @@ # gets everything in the logical feed (could be a lot of stuff) # (see <http://www.ietf.org/internet-drafts/draft-nottingham-atompub-feed-history-05.txt>) def get_everything! self.update! - + prev = @prev while prev prev.update! self.merge_entries! prev @@ -134,65 +122,63 @@ # TODO: add atom:source elements self << entry end end - # like #merge, but in place + # like #merge, but in place def merge! other_feed - [:id, :title, :subtitle, :updated, :rights, :logo, :icon].each { |p| - self.send("#{p}=", other_feed.send("#{p}")) - } + [:id, :title, :subtitle, :updated, :rights, :logo, :icon].each do |p| + if (v = other_feed.get(p)) + set p, v + end + end [:links, :categories, :authors, :contributors].each do |p| - other_feed.send("#{p}").each do |e| - self.send("#{p}") << e + other_feed.get(p).each do |e| + get(p) << e end end + @extensions = other_feed.extensions + merge_entries! other_feed end # merges "important" properties of this feed with another one, # returning a new feed def merge other_feed feed = self.clone feed.merge! other_feed - + feed end # fetches this feed's URL, parses the result and #merge!s # changes, new entries, &c. # # (note that this is different from Atom::Entry#updated! def update! raise(RuntimeError, "can't fetch without a uri.") unless @uri - - headers = {} - headers["Accept"] = "application/atom+xml" - headers["If-None-Match"] = @etag if @etag - headers["If-Modified-Since"] = @last_modified if @last_modified - res = @http.get(@uri, headers) + res = @http.get(@uri, "Accept" => "application/atom+xml") - if res.code == "304" + if @etag and res['etag'] == @etag # we're already all up to date return self elsif res.code == "410" raise Atom::FeedGone, "410 Gone (#{@uri})" elsif res.code != "200" raise Atom::HTTPException, "Unexpected HTTP response code: #{res.code}" end - + # we'll be forgiving about feed content types. - res.validate_content_type(["application/atom+xml", - "application/xml", + res.validate_content_type(["application/atom+xml", + "application/xml", "text/xml"]) @etag = res["ETag"] if res["ETag"] - @last_modified = res["Last-Modified"] if res["Last-Modified"] xml = res.body coll = REXML::Document.new(xml) @@ -201,29 +187,28 @@ # the feed hasn't been updated, don't do anything. if update_el and self.updated and self.updated >= Time.parse(update_el.text) return self end - coll = Atom::Feed.parse(coll, self.base.to_s) + coll = self.class.parse(coll.root, self.base.to_s) merge! coll - link = coll.links.find { |l| l["rel"] == "next" and l["type"] == "application/atom+xml" } - if link - abs_uri = @uri + link["href"] - @next = Feed.new(abs_uri.to_s, @http) + if abs_uri = next_link + @next = self.class.new(abs_uri.to_s, @http) end - link = coll.links.find { |l| l["rel"] == "previous" and l["type"] == "application/atom+xml" } - if link - abs_uri = @uri + link["href"] - @prev = Feed.new(abs_uri.to_s, @http) + if abs_uri = previous_link + @prev = self.class.new(abs_uri.to_s, @http) end self end - # adds an entry to this feed. if this feed already contains an + atom_link :previous_link, :rel => 'previous' + atom_link :next_link, :rel => 'next' + + # adds an entry to this feed. if this feed already contains an # entry with the same id, the newest one is used. def << entry existing = entries.find do |e| e.id == entry.id end @@ -234,8 +219,5 @@ @entries[@entries.index(existing)] = entry end end end end - -# this is here solely so you don't have to require it -require "atom/xml"