データ抽出処理 ++

前に作った Extract クラスに一工夫を加えてみた。
素直に Scraper::Base を使えって言われるとそうかもしれないけれど。


つい、こんな仕組みで動いているんだ、と気づくとそれに近いものを
作って試してみたくなるんだよね。ただ、利用目的に合わなければ、
「使わない」という選択もあり、だと思う。


でも、Ruby にはメソッドを上書きしてしまうこともできるし。。。
その点を考えると、よくできてるな、Ruby

ソースコード

require 'rubygems'
require 'hpricot'
require 'extract'
require 'pp'

text =<<EOD
<root>
  <title>extract test</title>
  <record>
    <item>
      <name>user01</name>
      <id>0</id>
      <date>2007/11/25</date>
      <comment>comment01 foobar</comment>
    </item>
    <item>
      <name>user02</name>
      <id>1</id>
      <date>2007/11/28</date>
      <comment>comment02 foobar</comment>
    </item>
    <item>
      <name>user03</name>
      <id>2</id>
      <date>2007/11/30</date>
      <comment>comment03 foobar</comment>
    </item>
  </record>
</root>
EOD

class ExtractBase
  @@instances = {}

  class << self
    attr_accessor :instances
  end

  def parse(text)
    define = @@instances[self.class]
    Extract.match :text => text do
      record(define[:options], &define[:block])
    end
  end

  def self.process(opt, &block)
    @@instances[self] = {:options => opt, :block => block}
  end
end

class Foo < ExtractBase
  process :regexp => '<item>(.+?)</item>' do
    item :name    => { :regexp => '<name>(.+?)</name>' }
    item :id      => { :regexp => '<id>(.+?)</id>' }
    item :date    => { :regexp => '<date>(.+?)</date>' }
    item :comment => { :regexp => '<comment>(.+?)</comment>' }
  end
end

foo = Foo.new
pp foo.parse(text)
# =>
# {:item=>
#   [{:date=>"2007/11/25",
#     :comment=>"comment01 foobar",
#     :name=>"user01",
#     :id=>"0"},
#    {:date=>"2007/11/28",
#     :comment=>"comment02 foobar",
#     :name=>"user02",
#     :id=>"1"},
#    {:date=>"2007/11/30",
#     :comment=>"comment03 foobar",
#     :name=>"user03",
#     :id=>"2"}],
#  :summary=>{}}