既存の EventMachine::Deferrable なクラスを薄くラップする

本格的に Deferrable なクラスを作りたいときは include EM::Deferrable するけど,そうではなく既存の Deferrable の上にちょっと乗せるだけみたいなときは EM::DefaultDeferrable を利用するといいらしい.
em-http-request を利用して非同期にリクエストを投げ,結果を Nokogiri でパースして例えばタイトルを表示する例.こんなかんじでいいんだろうか.

#!/usr/bin/ruby
# coding: utf-8
require 'em-http'
require 'nokogiri'

class HtmlDocument < EM::DefaultDeferrable
  attr_reader :http, :parser

  def initialize(http)
    @http = http
  end

  def succeed
    @parser = Nokogiri::HTML.parse @http.response
    super
  end
end

def get_document(uri)
  http = EM::HttpRequest.new(uri).get
  doc = HtmlDocument.new http
  http.callback { doc.succeed }
  http.errback { doc.fail }
  doc
end

EM.run do
  multi = EM::MultiRequest.new

  [
    'http://www.google.co.jp/',
    'http://www.hatena.ne.jp/h/o/g/e',
    'http://eagletmt.com/',
  ].each do |uri|
    doc = get_document uri
    doc.callback do
      puts "ok: #{doc.http.response_header.status}: #{doc.parser.xpath('//title').inner_text}"
    end
    doc.errback do
      puts "ng: #{doc.http.error}: #{doc.http.uri}"
    end
    multi.add doc
  end

  multi.callback do
    puts "succeeded #{multi.responses[:succeeded].size}/#{multi.requests.size}"
    EM.stop
  end
end

実行結果(最後の行以外の順番はバラつく可能性あり)

ng: unable to resolve server address: http://eagletmt.com:80/
ok: 200: Google
ok: 404: おさがしのページは見つかりませんでした - はてな
succeeded 2/3