Why the Ruby each iterator goes first in the execution?
Asked Answered
B

2

5

I've came across a weird thing doing simple tasks in Ruby. I just want to iterate the alphabet with the each method but the iteration goes first in the execution:

alfawit = ("a".."z")
puts "That's an alphabet: \n\n #{ alfawit.each { |litera| puts litera } } "

and this code results in this: (abbreviated)

a
b
c
⋮
x
y
z
That's an alphabet: 

 a..z 

Any ideas why it works like this or what supposedly I did wrong?

Thanks in advance.

Bug answered 21/2, 2017 at 9:46 Comment(2)
What's your expected result?Olive
Listing the alphabet after the "That's an alphabet" like it is done properly by Ursus. I had thought that I am able to nest the iteration the way I did it.Bug
E
5

Because your each call is interpolated in your string literal that's executed before the fixed string. Also, each returns an Enumerable, in fact you print even that. Try this one

alfawit = ("a".."z")
puts "That's an alphabet: \n\n"
alfawit.each { |litera| puts litera } 

or

puts "That's an alphabet: \n\n"
("a".."z").each { |litera| puts litera } 

you can use interpolation if you want but in this way

alfawit = ("a".."z")
puts "That's an alphabet: \n\n#{alfawit.to_a.join("\n")}"
Empedocles answered 21/2, 2017 at 9:50 Comment(2)
Thank you. I was struggling to understand that for a few days but that was so simple.Bug
My pleasure Sir :)Empedocles
O
3

You can easily see what's going on if you extract the interpolation part into a variable:

alfawit = ("a".."z")
foo = alfawit.each { |litera| puts litera }
puts "That's an alphabet: \n\n #{ foo } "

The second line is causing the trouble: each invokes the block for each element of the range and then returns the receiver, so that foo becomes alfawit.

Here's another way to get the desired result:

alfawit = "a".."z"
puts "That's an alphabet:", alfawit.to_a

puts outputs each argument on a new line, but for array arguments, it outputs each element on a new line. Result:

That's an alphabet:
a
b
c
⋮
x
y
z

Likewise, you can turn the range into an argument list via *:

alfawit = "a".."z"
puts "That's an alphabet:", *alfawit

That's equivalent to:

puts "That's an alphabet:", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
Olive answered 21/2, 2017 at 10:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.