Class: Atom::Feed

Inherits:
Element show all
Includes:
HasCategories, HasLinks, Enumerable
Defined in:
lib/atom/feed.rb

Overview

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"

Instance Attribute Summary collapse

Attributes inherited from Element

#base, #extensions

Instance Method Summary collapse

Methods included from HasCategories

included, #tag_with

Methods included from HasLinks

#find_link, included

Methods inherited from Element

#append_elem, attributes, #build, builders, def_get, def_set, do_parsing, #get, #get_atom_attrb, #get_atom_elem, #get_atom_elems, #get_elem, #get_elems, initters, is_atom_element, is_element, on_build, on_init, parse, #set, #set_atom_attrb, #to_s, #to_xml

Methods included from Parsers

#on_parse, #on_parse_attr, #on_parse_many, #on_parse_root, #parse_plain

Methods included from Converters

#atom_attrb, #atom_element, #atom_elements, #atom_link, #atom_string, #atom_time, #attrb, #build_plain, #element, #elements, #strings, #time

Constructor Details

#initialize(feed_uri = nil, http = Atom::HTTP.new) ⇒ Feed

Create a new Feed that can be found at feed_uri and retrieved using an Atom::HTTP object http



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/atom/feed.rb', line 74

def initialize feed_uri = nil, http = Atom::HTTP.new
  @entries = []
  @http = http

  if feed_uri
    @uri = feed_uri.to_uri
    self.base = feed_uri
  end

  super()
end

Instance Attribute Details

#etagObject (readonly)

conditional get information from the last fetch



44
45
46
# File 'lib/atom/feed.rb', line 44

def etag
  @etag
end

#last_modifiedObject (readonly)

conditional get information from the last fetch



44
45
46
# File 'lib/atom/feed.rb', line 44

def last_modified
  @last_modified
end

#nextObject (readonly)

the Atom::Feed pointed to by link



41
42
43
# File 'lib/atom/feed.rb', line 41

def next
  @next
end

#prevObject (readonly)

the Atom::Feed pointed to by link



39
40
41
# File 'lib/atom/feed.rb', line 39

def prev
  @prev
end

#uriObject (readonly)

Returns the value of attribute uri.



36
37
38
# File 'lib/atom/feed.rb', line 36

def uri
  @uri
end

Instance Method Details

#<<(entry) ⇒ Object

adds an entry to this feed. if this feed already contains an entry with the same id, the newest one is used.



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/atom/feed.rb', line 211

def << entry
  existing = entries.find do |e|
    e.id == entry.id
  end

  if not existing
    @entries << entry
  elsif not existing.updated or (existing.updated and entry.updated and entry.updated >= existing.updated)
    @entries[@entries.index(existing)] = entry
  end
end

#each(&block) ⇒ Object

iterates over a feed’s entries



87
88
89
# File 'lib/atom/feed.rb', line 87

def each &block
  @entries.each &block
end

#empty?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/atom/feed.rb', line 91

def empty?
  @entries.empty?
end

#get_everything!Object

gets everything in the logical feed (could be a lot of stuff) (see RFC 5005)



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/atom/feed.rb', line 97

def get_everything!
  self.update!

  prev = @prev
  while prev
    prev.update!

    self.merge_entries! prev
    prev = prev.prev
  end

  nxt = @next
  while nxt
    nxt.update!

    self.merge_entries! nxt
    nxt = nxt.next
  end

  self
end

#inspectObject

:nodoc:



68
69
70
# File 'lib/atom/feed.rb', line 68

def inspect # :nodoc:
  "<#{@uri} entries: #{entries.length} title='#{title}'>"
end

#merge(other_feed) ⇒ Object

merges “important” properties of this feed with another one, returning a new feed



148
149
150
151
152
153
154
# File 'lib/atom/feed.rb', line 148

def merge other_feed
  feed = self.clone

  feed.merge! other_feed

  feed
end

#merge!(other_feed) ⇒ Object

like #merge, but in place



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/atom/feed.rb', line 128

def merge! other_feed
  [: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.get(p).each do |e|
      get(p) << e
    end
  end

  @extensions = other_feed.extensions

  merge_entries! other_feed
end

#merge_entries!(other_feed) ⇒ Object

merges the entries from another feed into this one



120
121
122
123
124
125
# File 'lib/atom/feed.rb', line 120

def merge_entries! other_feed
  other_feed.each do |entry|
    # TODO: add atom:source elements
    self << entry
  end
end

#update!Object

fetches this feed’s URL, parses the result and #merge!s changes, new entries, &c.

(note that this is different from Atom::Entry#updated!

Raises:

  • (RuntimeError)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/atom/feed.rb', line 160

def update!
  raise(RuntimeError, "can't fetch without a uri.") unless @uri

  res = @http.get(@uri, "Accept" => "application/atom+xml")

  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",
                              "text/xml"])

  @etag = res["ETag"] if res["ETag"]

  xml = res.body

  coll = REXML::Document.new(xml)

  update_el = REXML::XPath.first(coll, "/atom:feed/atom:updated", { "atom" => Atom::NS } )

  # 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 = self.class.parse(coll.root, self.base.to_s)
  merge! coll

  if abs_uri = next_link
    @next = self.class.new(abs_uri.to_s, @http)
  end

  if abs_uri = previous_link
    @prev = self.class.new(abs_uri.to_s, @http)
  end

  self
end