Skip to content

Instantly share code, notes, and snippets.

@stujo
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stujo/7450a9f9e411cbdbc3e2 to your computer and use it in GitHub Desktop.
Save stujo/7450a9f9e411cbdbc3e2 to your computer and use it in GitHub Desktop.
Enumerator Playground
require 'fiber'
#https://practicingruby.com/articles/building-enumerable-and-enumerator
module FakeEnumerable
def select
result = []
each do |value|
result << value if yield(value)
end
result
end
def reduce sym_or_memo = nil
memo = 0
if sym_or_memo.is_a? Symbol
method_name = sym_or_memo
each do |value|
memo = memo.send(method_name, value)
end
elsif block_given?
memo = sym_or_memo unless sym_or_memo.nil?
each do |value|
memo = yield memo, value
end
end
memo
end
def map(&block)
if block_given?
result = []
each do |value|
result << yield(value)
end
result
else
FakeEnumerator.new(self, :map)
end
end
def sort_by
result = []
each do |value|
result << value
end
result.sort!{|a,b|
yield(a) <=> yield(b)
}
end
end
class FakeEnumerator
def initialize subject, method_name_symbol = nil
@subject = subject
@method_name_symbol = method_name_symbol
rewind
end
def with_index(&block)
results = []
index = 0
begin
while (v = self.next) do
results << yield(v, index)
index += 1
end
rescue StopIteration
end
results
end
def next
@fiber.resume.tap{raise StopIteration unless @fiber.alive?}
end
def rewind
@fiber = Fiber.new do
@subject.each do |element|
Fiber.yield element
end
end
end
end
class SortedList
include FakeEnumerable
def initialize
@data = []
end
def <<(new_element)
@data << new_element
@data.sort!
self
end
def each
if block_given?
@data.each { |e| yield(e) }
else
FakeEnumerator.new(self, :each)
end
end
end
require "minitest/autorun"
describe "FakeEnumerable" do
before do
@list = SortedList.new
# will get stored interally as 3,4,7,13,42
@list << 3 << 13 << 42 << 4 << 7
end
it "supports map" do
@list.map { |x| x + 1 }.must_equal([4,5,8,14,43])
end
it "supports sort_by" do
# ascii sort order
@list.sort_by { |x| x.to_s }.must_equal([13, 3, 4, 42, 7])
end
it "supports select" do
@list.select { |x| x.even? }.must_equal([4,42])
end
it "supports reduce" do
@list.reduce(:+).must_equal(69)
@list.reduce { |s,e| s + e }.must_equal(69)
@list.reduce(-10) { |s,e| s + e }.must_equal(59)
end
end
describe "FakeEnumerator" do
before do
@list = SortedList.new
@list << 3 << 13 << 42 << 4 << 7
end
it "supports next" do
enum = @list.each
enum.next.must_equal(3)
enum.next.must_equal(4)
enum.next.must_equal(7)
enum.next.must_equal(13)
enum.next.must_equal(42)
assert_raises(StopIteration) { (enum.next).tap{|x| puts x} }
end
it "supports rewind" do
enum = @list.each
4.times { enum.next }
enum.rewind
2.times { enum.next }
enum.next.must_equal(7)
end
it "supports with_index" do
enum = @list.map
expected = ["0. 3", "1. 4", "2. 7", "3. 13", "4. 42"]
enum.with_index { |e,i| "#{i}. #{e}" }.must_equal(expected)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment