RSS を YAML に変換する#2
の続きです。nuna さんがコメントで色々教えてくれました。
- バージョンが異なるフィードを、バージョンを意識せずに parse するには require を複数書くとよい (http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.ja にマニュアルあり。)
- YAML にするときにオブジェクトをそのまま渡すと、YAML で復元した側がそのオブジェクトのクラスを必要とするようになってしまう。これを回避するには RSS オブジェクトを Hash にすると良い。
- Hash にするには RSS::RDF に to_hash などを追加定義するとよい
とのことです。そこで、昨日のコードを書き替えてみました。
- require で rss/1.0 に加えて rss/2.0 も追加したので、RSS 2.0 を parse できるようになりました。
- to_hash メソッドの追加は RSS::Hashable というモジュールを使って Mixin でやってみました。RSS::RDF (1.0 用のクラス) と RSS::Rss に全く同じメソッドを追加する必要があったので。
#!/usr/local/bin/ruby require 'open-uri' require 'rss/1.0' require 'rss/2.0' require 'yaml' module RSS::Hashable def to_hash { :channel => { :title => self.channel.title, :link => self.channel.link, :description => self.channel.description }, :items => self.items.map do |item| { :title => item.title, :link => item.link, :description => item.description } end } end end class RSS::RDF include RSS::Hashable end class RSS::Rss include RSS::Hashable end class RSS2YAML def initialize(url) @url = url end def to_hash rss = self.parse_rss(@url) rss.to_hash end def to_yaml self.to_hash.to_yaml end def get_remote(url) begin return Kernel.open(@url).read rescue OpenURI::HTTPError return nil end end def parse_rss(url) content = self.get_remote(url) if content begin return RSS::Parser::parse(content) rescue RSS::InvalidRSSError return nil end end end public :to_yaml protected :get_remote, :parse_rss end if ARGV.size != 1 puts "Usage: ruby rss2yaml.rb <url>" exit end puts RSS2YAML.new(ARGV.shift).to_yaml
これで出力の yaml は ruby に依存しなくなりました。nuna さんありがとうございました。
RSS::Hashable の中身がちょっと Perl チックな書き方なのですが、こういうものでしょうか。Ruby は既存のクラスにメソッドを追加したりモジュールを Mixin したりするのが楽でいいですね。
ところで「たのしい Ruby」には普通は"モジュールの中では self は使いません" という記述があるのですが、Mixin 用モジュールでは使わないと書けないようなきもしますがどうなんでしょう。