Enumerator with index
Imagine a situation where you have a collection of string that you want to map to tag objects, but you want the first one to have a default flag.
first = true
tags = line.split(",").map do |name|
tag = Tag.new(default: first, name: name)
first = false
tag
end
Alright, that works, but it’s not pretty. Is there a way to make it nicer?
Of course there is, at least for ruby 1.9.3 and higher. If you call a map
method on a collection without any block it returns an Enumerator
class since ruby 1.9.
And a method Enumerator#with_index
that was introduced in ruby 1.9.3 adds an index to our iteration, so combining those two together we get
tags = line.split(",").map.with_index do |name, index|
Tag.new(default: index == 0, name: tag_name)
end
Elegant and much easier to read. Enumerator
is very powerful and helpful concept and with the combination of Enumerable
module only the sky is the limit.
Also omitting the block and returning Enumerator
instead of an array works not just for map
, but for similar methods like select
, reject
, flat_map
, group_by
and others. Check out the docs and make your code nicer.