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 72 72: def self.parse xml, base = "" 73: if xml.respond_to? :to_atom_entry 74: xml.to_atom_feed(base) 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 214 214: def << entry 215: existing = entries.find do |e| 216: e.id == entry.id 217: end 218: 219: if not existing 220: @entries << entry 221: elsif not existing.updated or (existing.updated and entry.updated and entry.updated >= existing.updated) 222: @entries[@entries.index(existing)] = entry 223: end 224: 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
merges "important" properties of this feed with another one, returning a new feed
# File lib/atom/feed.rb, line 148 148: def merge other_feed 149: feed = self.clone 150: 151: feed.merge! other_feed 152: 153: feed 154: 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.
# File lib/atom/feed.rb, line 158 158: def update! 159: raise(RuntimeError, "can't fetch without a uri.") unless @uri 160: 161: headers = {} 162: headers["If-None-Match"] = @etag if @etag 163: headers["If-Modified-Since"] = @last_modified if @last_modified 164: 165: res = @http.get(@uri, headers) 166: 167: if res.code == "304" 168: # we're already all up to date 169: return self 170: elsif res.code == "410" 171: raise Atom::FeedGone, "410 Gone (#{@uri})" 172: elsif res.code != "200" 173: raise Atom::HTTPException, "Unexpected HTTP response code: #{res.code}" 174: end 175: 176: unless res.content_type.match(/^application\/atom\+xml/) 177: raise Atom::HTTPException, "Unexpected HTTP response Content-Type: #{res.content_type} (wanted application/atom+xml)" 178: end 179: 180: @etag = res["Etag"] if res["Etag"] 181: @last_modified = res["Last-Modified"] if res["Last-Modified"] 182: 183: xml = res.body 184: 185: coll = REXML::Document.new(xml) 186: 187: update_time = Time.parse(REXML::XPath.first(coll, "/atom:feed/atom:updated", { "atom" => Atom::NS } ).text) 188: 189: # the feed hasn't been updated, don't bother 190: if self.updated and self.updated >= update_time 191: return self 192: end 193: 194: coll = Atom::Feed.parse(coll, self.base.to_s) 195: merge! coll 196: 197: link = coll.links.find { |l| l["rel"] = "next" and l["type"] == "application/atom+xml" } 198: if link 199: abs_uri = @uri + link["href"] 200: @next = Feed.new(abs_uri.to_s, @http) 201: end 202: 203: link = coll.links.find { |l| l["rel"] = "previous" and l["type"] == "application/atom+xml" } 204: if link 205: abs_uri = @uri + link["href"] 206: @prev = Feed.new(abs_uri.to_s, @http) 207: end 208: 209: self 210: end