少し前にRSSフィードをパースするgem、Feedzirraの紹介記事で次のようなことを書きました。
そうすると
update
メソッドが使えるようになります。このような流れで更新された記事だけを取り出すことができるようになりました。なお、
Feedzirra::Parser::RSS
以外にもFeedzirra::Parser::Atom
などのパーサーがあるのですが、違うフォーマットでもいい感じにやってくれるから大丈夫!という旨がこちらのコメントで確認できます。rss - Ruby - Feedzirra and updates - Stack Overflow
ソース読めばわかるんでしょうがまだ読んでいないという。今度読みます。
なので、早速ソースコードを読んでみました。
何を調べるのか?
整理すると、フィードの更新の際に用意するパーサーオブジェクトがFeedzirra::Parser::RSS
であろうがFeedzirra::Parser::Atom
だろうが、どんなフォーマットのフィードでも更新できるらしいが、それはなぜかというところです。
そもそも新規の取得時は?
新規取得のときはこのような使い方をします。
feed = Feedzirra::Feed.fetch_and_parse(feed_urls.first)
このfetch_and_parse
が何をしているのかを追ってみます。
# feed.rb
def self.fetch_and_parse(urls, options = {})
# ...
url_queue.slice!(0, 30).each do |url|
add_url_to_multi(multi, url, url_queue, responses, options)
end
# ...
end
def self.add_url_to_multi(multi, url, url_queue, responses, options)
# ...
klass = determine_feed_parser_for_xml(xml)
# ...
end
def self.determine_feed_parser_for_xml(xml)
start_of_doc = xml.slice(0, 2000)
feed_classes.detect {|klass| klass.able_to_parse?(start_of_doc)}
end
お!どのパーサー使うか、というような話がでてきました。fetch_and_parse
の奥でパース直前にフィードのXMLからパーサーを特定するようなロジックが入っていました。このdetermine_feed_parser_for_xml
でRSSフィードのフォーマットに応じてFeedzirra::Parser::RSS
やFeedzirra::Parser::Atom
などが返ってくるようです。
更新のとき
更新のときはこう使います。
feed = Feedzirra::Parser::RSS.new
# ...
Feedzirra::Feed.update(feed)
このupdate
を追ってみます。
def self.update(feeds, options = {})
# ...
feed_queue.slice!(0, 30).each do |feed|
add_feed_to_multi(multi, feed, feed_queue, responses, options)
end
# ...
end
def self.add_feed_to_multi(multi, feed, feed_queue, responses, options)
# ...
updated_feed = Feed.parse(c.body_str)
# ...
end
def self.parse(xml)
if parser = determine_feed_parser_for_xml(xml)
parser.parse(xml)
else
raise NoParserAvailable.new("No valid parser for XML.")
end
end
ここでもまたdetermin_feed_parser_for_xml
が呼ばれてた!
そういうわけで、どのクラスを渡しても実際のパース前に適切なロジックが選択されることに間違いないということがわかりました。
よかった。すっきりしました。