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.

Stefan
  • 109,145
  • 14
  • 143
  • 218
Michalko
  • 53
  • 3

2 Answers2

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")}"
Ursus
  • 29,643
  • 3
  • 33
  • 50
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"
Stefan
  • 109,145
  • 14
  • 143
  • 218