Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1

40 | Chapter 1: Foundational Techniques


The signature ofEnumerator.newisEnumerator.new(obj,method,*args), whereobjis
the object to enumerate over,methodis the base iterator, andargsare any arguments
that the iterator receives. As an example, you could write amap_with_indexfunction
(a version ofmapthat passes the object and its index to the given block) with the fol-
lowing code:


require "enumerator"
module Enumerable
def map_with_index &b
enum_for(:each_with_index).map(&b)
end
end

puts ("a".."f").map_with_index{|letter, i| [letter, i]}.inspect
# >> [["a", 0], ["b", 1], ["c", 2], ["d", 3], ["e", 4], ["f", 5]]

Theenum_formethod returns anEnumeratorobject whoseeachmethod functions like
the each_with_indexmethod of the original object. That Enumeratorobject has
already been extended with the instance methods fromEnumerable, so we can just
callmap on it, passing the given block.


Enumeratoralso adds some convenience methods toEnumerable, which are useful to
have.Enumerable#each_slice(n) iterates over slices of the array,n-at-a-time:


(1..10).each_slice(3){|slice| puts slice.inspect}
# >> [1, 2, 3]
# >> [4, 5, 6]
# >> [7, 8, 9]
# >> [10]

Similarly,Enumerable#each_cons(n)moves a “sliding window” of sizenover the col-
lection, one at a time:


(1..10).each_cons(3){|slice| puts slice.inspect}
# >> [1, 2, 3]
# >> [2, 3, 4]
# >> [3, 4, 5]
# >> [4, 5, 6]
# >> [5, 6, 7]
# >> [6, 7, 8]
# >> [7, 8, 9]
# >> [8, 9, 10]

Enumeration is getting a facelift in Ruby 1.9.Enumeratoris becoming part of the core
language. In addition, iterators return anEnumeratorobject automatically if they are
not given a block. In Ruby 1.8, you would usually do the following to map over the
values of a hash:


hash.values.map{|value| ... }

This takes the hash, builds an array of values, and maps over that array. To remove
the intermediate step, you could use anEnumerator:


hash.enum_for(:each_value).map{|value| ... }
Free download pdf