4.18.3. Kooperující procedury

class Coroutine
    def initialize(data = {})
        @data = data
        callcc do |@continue|
            return
        end
        yield self
    end

    attr_reader :stopped

    def run
        callcc do |@stopped|
            continue
        end
    end

    def stop
        @stopped.call
    end

    def resume(other)
        callcc do |@continue|
            other.continue(self)
        end
    end

    def continue(from = nil)
        @stopped = from.stopped if not @stopped and from
        @continue.call
    end

    def [](name)
        @data[name]
    end

    def []=(name, value)
        @data[name] = value
    end

    protected :stopped, :continue

end

count = (ARGV.shift || 1000).to_i
input = (1..count).map { (rand * 10000).round.to_f / 100}
Producer = Coroutine.new do |me|
    loop do
        1.upto(6) do
            me[:last_input] = input.shift
            me.resume(Printer)
        end
        input.shift # discard every seventh input number
    end
end
Printer = Coroutine.new do |me|
    loop do
        1.upto(8) do
            me.resume(Producer)
            if Producer[:last_input]
                print Producer[:last_input], "\t"
                Producer[:last_input] = nil
            end
            me.resume(Controller)
        end
        puts
    end
end
Controller = Coroutine.new do |me|
    until input.empty? do
        me.resume(Printer)
    end
end
Controller.run
puts

Licence Creative Commons
Tento dokument Ruby, jehož autorem je Radek Hnilica, podléhá licenci Creative Commons Uveďte autora-Nevyužívejte dílo komerčně-Zachovejte licenci 3.0 Česká republika .