Slide 1

Slide 1 text

Review Ruby s Iterator with Enumerator Photo by Tine Ivanič on Unsplash

Slide 2

Slide 2 text

WEB DEVELOPER GAME DEVELOPER ૵ ࣌ ݭ໵ @elct9620

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

As a Ruby developer, We use #each every day

Slide 5

Slide 5 text

BUT How it works?

Slide 6

Slide 6 text

#iterator Photo by Joel Fulgencio on Unsplash

Slide 7

Slide 7 text

def iterator(&block) yield 1 yield 2 yield 3 end

Slide 8

Slide 8 text

VALUE rb_block_call(VALUE obj, ID mid, int argc, const VALUE * argv, VALUE (*bl_proc) (ANYARGS), VALUE data2) { struct iter_method_arg arg; arg.obj = obj; arg.mid = mid; arg.argc = argc; arg.argv = argv; return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2); } The block call is iterate in ruby

Slide 9

Slide 9 text

def each(&block) @i = 0 yield @i += 1 until @i >= 10 end

Slide 10

Slide 10 text

#loop vs #while

Slide 11

Slide 11 text

static VALUE loop_i(void) { for (;;) { rb_yield_0(0, 0); } return Qnil; } Loop is a method with a block

Slide 12

Slide 12 text

#enumerator Photo by Glenn Carstens-Peters on Unsplash

Slide 13

Slide 13 text

[].each # => #

Slide 14

Slide 14 text

Why we need Enumerator?

Slide 15

Slide 15 text

enum = [1, 2, 3].to_enum enum.next # => 1 enum.next # => 2 enum.next # => 3

Slide 16

Slide 16 text

Enumerator vs Enumerable

Slide 17

Slide 17 text

class Backpack include Enumerable def initialize(items) @items = items end def each(&block) @items.each(&block) end end backpack = Backpack.new([:water, :apple]) backpack.map {}

Slide 18

Slide 18 text

#generator Photo by m0851 on Unsplash

Slide 19

Slide 19 text

#to_enum vs Enumerator.new

Slide 20

Slide 20 text

class List def each(&block) #... end end List.new.to_enum # => #:each>

Slide 21

Slide 21 text

class List def pop(&block) #... end end List.new.to_enum(:pop) # => #:pop>

Slide 22

Slide 22 text

If Enumerator.new didn t have target ruby will create a Generator

Slide 23

Slide 23 text

Enumerator.new do |yielder| yielder << 1 yielder << 2 end

Slide 24

Slide 24 text

Why we need Yielder?

Slide 25

Slide 25 text

enum = Enumerator.new do yield 1 yield 2 end puts enum.to_a # => no block given (yield) (LocalJumpError)

Slide 26

Slide 26 text

class Yielder def initialize(&block) @proc = block.to_proc end def <<(value) @proc.call(value) self end end

Slide 27

Slide 27 text

class Generator def initialize(&block) @proc = block.to_proc end def each(&_block) yielder = Yielder.new { |x| yield x } @proc.call(yielder) end end

Slide 28

Slide 28 text

#lazy Photo by Kate Stone Matheson on Unsplash

Slide 29

Slide 29 text

It is hard to figure out it, but useful

Slide 30

Slide 30 text

class Backpack def each(&block) yield p(1) yield p(2) yield p(3) end end backpack = Backpack.new.to_enum backpack.map(&:rect).take(1).to_a backpack.lazy.map(&:rect).take(1).to_a

Slide 31

Slide 31 text

class Backpack def each(&block) yield p(1) yield p(2) yield p(3) end end backpack = Backpack.new.to_enum backpack.map(&:rect).take(1).to_a backpack.lazy.map(&:rect).take(1).to_a

Slide 32

Slide 32 text

backpack.map(&:rect).take(1).to_a # => 1 # => 2 # => 3 backpack.lazy.map(&:rect).take(1).to_a # => 1

Slide 33

Slide 33 text

backpack.take(1).to_a # => 1 backpack.lazy.take(1).to_a # => 1

Slide 34

Slide 34 text

backpack = Backpack.new.to_enum backpack.lazy.reverse_each.take(1).to_a # => 1 # => 2 # => 3

Slide 35

Slide 35 text

And last, let s discuss implement #lazy in Ruby

Slide 36

Slide 36 text

Thanks