Skip to content

Instantly share code, notes, and snippets.

@maxjacobson
Last active November 18, 2017 15:31
Show Gist options
  • Save maxjacobson/b94d3175a2c1b41c0d44382073cb2941 to your computer and use it in GitHub Desktop.
Save maxjacobson/b94d3175a2c1b41c0d44382073cb2941 to your computer and use it in GitHub Desktop.

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment