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