みなさん、こんにちは(・∀・) rubyの標準RSSライブラリが思ったよりも高機能でびっくりしたので、gemを使わずにAtomとRssのParserを作ってみたので、そのへんのやり方をメモしておきますm( )m
Ruby標準のRSSライブラリ
標準ライブラリを使用する場合は、下記のような形でhttpリクエストを送信したParseされたRSSフィードを取得することができます👀
require 'rss' rss_source = Net::HTTP.get(URI.parse(endpoint)) rss = RSS::Parser.parse(rss_source) => #<RSS::Rss:0x00007fe3dfcc0bd0...
RSS::Parser.parse
の返り値は、引数で渡されたRSSの形式によって
、Rssの場合はRSS::Rss
、Atomの場合は、RSS::Atom::Feed
のオブジェクトが返却されます。(デフォルトでAtomまで対応してる🙌)
厳密には、下記とのこと
下記に詳細が乗っています👀
https://docs.ruby-lang.org/ja/latest/library/rss.html
共通のプロパティを持つオブジェクトを返却するRSSParserを作ってみる
標準ライブラリでAtomでもRssでも共通のオブジェクトを返却するRSSParserを作ってみようと思います👩🔧
イメージは下記のような感じ👀
# AtomでもRssでもParsedItemのオブジェクトが返却される RssCliant.new(endpoint).parsed_items => [#<ParsedItem:0x00007fe3e2e3ab48 @description="みなさん、...", @eye_catching_image="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png", @link="https://madogiwa0124.hatenablog.com/entry/2019/03/09/194825", @published_at=2019-03-09 19:48:25 +0900, @title="vue-cliで作ったアプリをGithub Pagesでサクッとリリースする">, #<ParsedItem:0x00007fe3e1c0ce08 @description= "自分が作っている...", @eye_catching_image="https://cdn-ak.f.st-hatena.com/images/fotolife/m/madogiwa0124/20190303/20190303213625.gif", @link="https://madogiwa0124.hatenablog.com/entry/2019/03/03/214203", @published_at=2019-03-03 21:42:03 +0900, @title="railsとVueを使って無限スクロール機能を実装するMEMO🌀">,
まずはCliant部分を作ってみる
まずは下記のようなRssCliant
をというClassを作ってみました👀
endpointを受け取って標準ライブラリを使ってParse、その後AtomかRssかによって使用するParserを切り替え共通のオブジェクトを返却します。
class RssClient def initialize(endpoint) @endpoint = endpoint @rss_source = Net::HTTP.get(URI.parse(endpoint)) end attr_reader :endpoint, :rss_source # 不正な形式だった場合に、バリデーションなしでParseする def parsed_rss! RSS::Parser.parse(rss_source) rescue RSS::InvalidRSSError RSS::Parser.parse(rss_source, false) end def parsed_items parsed_xml = parsed_rss! # オブジェクトのClass名でAtom or Rss用のParserを使って共通のオブジェクトにParse case parsed_xml.class.name when 'RSS::Atom::Feed' then Parser::Atom.call(parsed_xml) when 'RSS::Rss' then Parser::Rss.call(parsed_xml) else [] end end end
Atom or RssのParser部分
Rss.parse
でParseされたXMLを引数をもとに、build_parsed_item
でPasedItem
という共通のオブジェクトを生成し、それらのリストを返却するようにしています🙌
他の形式に対応する場合はParser::Hoge
が増えていくようなイメージですね👀
※またAtomの場合は、記事のアイキャッチ画像の取得方法が、ちょっと不明だったので一旦nil
を設定するようにしてます💦
Rss
class Parser::Rss def self.call(parsed_xml) new.call(parsed_xml) end def call(parsed_xml) @parsed_xml = parsed_xml items end attr_reader :parsed_xml def items @items = parsed_xml.items.map { |item| build_parsed_item(item) } end def build_parsed_item(item) Parser::ParsedItem.new( title: item.title, description: item.description, published_at: item.pubDate, link: item.link, eye_catching_image: item.enclosure&.url ) end end
Atom
class Parser::Atom def self.call(parsed_xml) new.call(parsed_xml) end def call(parsed_xml) @parsed_xml = parsed_xml items end attr_reader :parsed_xml def items @items = parsed_xml.entries.map { |entry| build_parsed_item(entry) } end def build_parsed_item(item) Parser::ParsedItem.new( title: item.title.content, description: item.content.content, published_at: item.published.content, link: item.link.href, eye_catching_image: nil # AtomにアイキャッチのURLなさそうなので一旦NULLを設定 ) end end
完成形
これでイメージどおりの完成形ができました🙌
# AtomでもRssでもParsedItemのオブジェクトが返却される RssCliant.new(endpoint).parsed_items => [#<ParsedItem:0x00007fe3e2e3ab48 @description="みなさん、...", @eye_catching_image="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png", @link="https://madogiwa0124.hatenablog.com/entry/2019/03/09/194825", @published_at=2019-03-09 19:48:25 +0900, @title="vue-cliで作ったアプリをGithub Pagesでサクッとリリースする">, #<ParsedItem:0x00007fe3e1c0ce08 @description= "自分が作っている...", @eye_catching_image="https://cdn-ak.f.st-hatena.com/images/fotolife/m/madogiwa0124/20190303/20190303213625.gif", @link="https://madogiwa0124.hatenablog.com/entry/2019/03/03/214203", @published_at=2019-03-03 21:42:03 +0900, @title="railsとVueを使って無限スクロール機能を実装するMEMO🌀">,
おわりに
今回はRubyの標準ライブラリだけを使ってRssParserを実装してみました。RssParserはFeedjira等のGemが有名ですが、そんなに凝ったことしないのであればRubyの標準ライブラリが使いやすく高機能なので充分なのでは?という気持ちになりました🙌
他にも標準ライブラリには便利そうな機能がありそうだったので、ちょっと見てみると良さそうですね👀