Class | Atom::Feed |
In: |
lib/atom/feed.rb
|
Parent: | Atom::Element |
A feed of entries. As an Atom::Element, it can be manipulated using accessors for each of its child elements. You can set them with any object that makes sense; they will be returned in the types listed.
Feeds have the following children:
id: | a universally unique IRI which permanently identifies the feed |
title: | a human-readable title (Atom::Text) |
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) |
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"
etag | [R] | conditional get information from the last fetch |
last_modified | [R] | conditional get information from the last fetch |
next | [R] | the Atom::Feed pointed to by link[@rel=‘next’] |
prev | [R] | the Atom::Feed pointed to by link[@rel=‘previous’] |
uri | [R] |
Create a new Feed that can be found at feed_uri and retrieved using an Atom::HTTP object http
# File lib/atom/feed.rb, line 82 82: def initialize feed_uri = nil, http = Atom::HTTP.new 83: @entries = [] 84: @http = http 85: 86: if feed_uri 87: @uri = feed_uri.to_uri 88: self.base = feed_uri 89: end 90: 91: super "feed" 92: end
parses XML fetched from base into an Atom::Feed
# File lib/atom/feed.rb, line 70 70: def self.parse xml, base = "" 71: if xml.respond_to? :to_atom_entry 72: xml.to_atom_feed(base) 73: elsif xml.respond_to? :read 74: self.parse(xml.read) 75: else 76: REXML::Document.new(xml.to_s).to_atom_feed(base) 77: end 78: end
adds an entry to this feed. if this feed already contains an entry with the same id, the newest one is used.
# File lib/atom/feed.rb, line 218 218: def << entry 219: existing = entries.find do |e| 220: e.id == entry.id 221: end 222: 223: if not existing 224: @entries << entry 225: elsif not existing.updated or (existing.updated and entry.updated and entry.updated >= existing.updated) 226: @entries[@entries.index(existing)] = entry 227: end 228: end
iterates over a feed‘s entries
# File lib/atom/feed.rb, line 95 95: def each &block 96: @entries.each &block 97: end
gets everything in the logical feed (could be a lot of stuff) (see <www.ietf.org/internet-drafts/draft-nottingham-atompub-feed-history-05.txt>)
# File lib/atom/feed.rb, line 101 101: def get_everything! 102: self.update! 103: 104: prev = @prev 105: while prev 106: prev.update! 107: 108: self.merge_entries! prev 109: prev = prev.prev 110: end 111: 112: nxt = @next 113: while nxt 114: nxt.update! 115: 116: self.merge_entries! nxt 117: nxt = nxt.next 118: end 119: 120: self 121: end
like merge, but in place
# File lib/atom/feed.rb, line 132 132: def merge! other_feed 133: [:id, :title, :subtitle, :updated, :rights].each { |p| 134: self.send("#{p}=", other_feed.send("#{p}")) 135: } 136: 137: [:links, :categories, :authors, :contributors].each do |p| 138: other_feed.send("#{p}").each do |e| 139: self.send("#{p}") << e 140: end 141: end 142: 143: merge_entries! other_feed 144: end
merges the entries from another feed into this one
# File lib/atom/feed.rb, line 124 124: def merge_entries! other_feed 125: other_feed.each do |entry| 126: # TODO: add atom:source elements 127: self << entry 128: end 129: 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!
# File lib/atom/feed.rb, line 160 160: def update! 161: raise(RuntimeError, "can't fetch without a uri.") unless @uri 162: 163: headers = {} 164: headers["Accept"] = "application/atom+xml" 165: headers["If-None-Match"] = @etag if @etag 166: headers["If-Modified-Since"] = @last_modified if @last_modified 167: 168: res = @http.get(@uri, headers) 169: 170: # we'll be forgiving about feed content types. 171: res.validate_content_type(["application/atom+xml", 172: "application/xml", 173: "text/xml"]) 174: 175: if res.code == "304" 176: # we're already all up to date 177: return self 178: elsif res.code == "410" 179: raise Atom::FeedGone, "410 Gone (#{@uri})" 180: elsif res.code != "200" 181: raise Atom::HTTPException, "Unexpected HTTP response code: #{res.code}" 182: end 183: 184: @etag = res["Etag"] if res["Etag"] 185: @last_modified = res["Last-Modified"] if res["Last-Modified"] 186: 187: xml = res.body 188: 189: coll = REXML::Document.new(xml) 190: 191: update_el = REXML::XPath.first(coll, "/atom:feed/atom:updated", { "atom" => Atom::NS } ) 192: 193: # the feed hasn't been updated, don't do anything. 194: if update_el and self.updated and self.updated >= Time.parse(update_el.text) 195: return self 196: end 197: 198: coll = Atom::Feed.parse(coll, self.base.to_s) 199: merge! coll 200: 201: link = coll.links.find { |l| l["rel"] = "next" and l["type"] == "application/atom+xml" } 202: if link 203: abs_uri = @uri + link["href"] 204: @next = Feed.new(abs_uri.to_s, @http) 205: end 206: 207: link = coll.links.find { |l| l["rel"] = "previous" and l["type"] == "application/atom+xml" } 208: if link 209: abs_uri = @uri + link["href"] 210: @prev = Feed.new(abs_uri.to_s, @http) 211: end 212: 213: self 214: end