cool.ioをFiberと組みあわせる

valaのGIOのasync関数が良かったので、ruby+cool.ioでも
そういう書き方をやってみた。

#!/usr/bin/env ruby

require 'fiber'
require 'uri'
require 'cool.io'


class HTTPRequest
  def initialize(uri, method=:GET)
    abort "invalid uri: #{uri}" unless uri.kind_of? URI
    @method=method
    @uri=uri
  end

  def host_port
    [@uri.host, @uri.port]
  end

  def to_s
"#{@method} #{@uri.path} HTTP/1.1\r\n"+
"\r\n"+
"\r\n"
  end
end


class FiberLogicSocket < Coolio::TCPSocket
  attr_accessor :fiber
  [:on_connect, :on_write_complete, :on_read].each do |m|
    define_method m do |*args|
      p m
      @fiber.resume(*args) # 引数を渡してfiberを再開する
    end
  end
end


if $0==__FILE__ then

  if ARGV.empty? then
    puts "usage: $0 url"
    exit
  end
  url=ARGV.shift

  request=HTTPRequest.new(URI.parse url)
  so=FiberLogicSocket.connect(*request.host_port)
  
  so.fiber=Fiber.new do
    # resume from on_connect

    so.write request.to_s # non block 
    Fiber.yield # wait for on_write_complete

    while true do
      data=Fiber.yield # wait for on_read

      p data
    end
  end

  # main loop
  l=Coolio::Loop.default
  l.attach so
  l.run

end

valaと同じような感じにするにはもっとがんばって書かないといけなくなるので、
妥協してこんな感じになった。
非同期IOのコールバックに分散して記述することになるロジックをFiberの中に固めるという理屈でございます。