Fiberっていうかコルーチンはこういうのに向いてるよなー。
いまなにやってるのか情報を持ち回すんじゃなくて、制御自体がそれを持っている。状態遷移マシンとか書くよりも、コルーチンでいったん休むほうがすっきり。
class Emitter def initialize @fiber = Fiber.new do |it| @plist = do_pop(it) end end attr_reader :plist def push(it) @fiber.resume(it) end def on_value(obj) push(obj) end def on_stag(name) push(name.intern) end def on_etag(name) push(('etag_' + name).intern) end def dict hash = Hash.new while key = pop_until(:etag_dict) hash[key] = pop end hash end def array ary = Array.new while elem = pop_until(:etag_array) ary.push(elem) end ary end def pop_until(symbol) it = pop return it unless Symbol === it return nil if it == symbol raise RuntimeError end def pop do_pop(Fiber.yield) end def do_pop(it) case it when :dict dict when :array array else it end end end