Will:
#!/usr/bin/env ruby
class Fountain
def self.x=(x)
@x = x
end
def self.x
@x
end
def initialize(&block)
@block = block
@yielder = Object.new
def @yielder.yield(x)
Fountain.x = x
Fiber.yield
end
end
def next
Fiber.new do
@block.call(@yielder)
end.resume
Fountain.x
end
end
fountain_of_faces =
Fountain.new do |yielder|
# an infinite loop!!!
#
loop do
yielder.yield(%w[:) :# :/ :( :D].sample)
end
end
orig_fountain =
Enumerator.new do |yielder|
# an infinite loop!!!
#
loop do
yielder.yield(%w[:) :# :/ :( :D].sample)
end
end
p "ORIG ENUMERATOR:"
3.times do
p orig_fountain.next
end
p "OUR FOUNTAIN:"
3.times do
p fountain_of_faces.next
end
boo yah.
max:
small patch:
class Fountain
def self.x=(x)
@x = x
end
def self.x
@x
end
def initialize(&block)
@yielder = Object.new
def @yielder.yield(x)
Fountain.x = x
Fiber.yield
end
@fiber = Fiber.new do
block.call(@yielder)
end
end
def next
@fiber.resume
Fountain.x
end
end
we want to make sure it’s the same fiber each time we call next
so that it’s the same invocation of block that we’re yielding and resuming, so that the state of the block can be maintained. the pain is felt if your enumerator is meant to provide non-random data, eg:
numbers =
Fountain.new do |yielder|
4000.times do |n|
yielder.yield(n)
end
end
p "OUR FOUNTAIN:"
3.times do
p numbers.next
end
we want to make sure it doesn’t provide:
0
0
0