Skip to content

Instantly share code, notes, and snippets.

@joshsarna
Last active February 26, 2019 18:03
Show Gist options
  • Save joshsarna/721d878063cf810c6b9021c96047f20f to your computer and use it in GitHub Desktop.
Save joshsarna/721d878063cf810c6b9021c96047f20f to your computer and use it in GitHub Desktop.

When looping in ruby, you have many options. It's common to see something like |variable_name| on the same line as the loop is defined: this is called a block variable. It's a variable we only have access to inside the loop, and it changes each time through the loop. We see this most often in an each loop.

fruits = ["apple", "pear", "grape", "mango"]

fruits.each do |fruit|
  p fruit
end

Our output looks like this:

"apple"
"pear"
"grape"
"mango"

If you were to try to print fruit outside of the loop (for example on the line after the end statement), you would get an undefined method or variable error.

We can read fruits.each do |fruit| as "for each fruit in our fruit array," that is, the the block variable is an instance or element from the array. We actually don't need the block variable if we don't plan on using the fruits themselves in our loop. We can write:

fruits = ["apple", "pear", "grape", "mango"]

fruits.each do
  p "hello"
end

The loop still runs four times, since there are four elements in the array, but all we end up with is the string "hello" printed to the terminal four times.

On the other hand, we can use two block variables in an each loop if we also want to keep track of the index at where each element occurs. That looks a little different:

fruits = ["apple", "pear", "grape", "mango"]

fruits.each_with_index do |fruit, index|
  p "#{index}. #{fruit}"
end

Our output is:

"0. apple"
"1. pear"
"2. grape"
"3. mango"

Block variables are almost exclusively used with each loops, but their function of keeping track of an index actually exists in other loop types as well. It's common to see a times loop with an index, like this:

i = 0

5.times do
  p i
  i += 1
end

Our output is:

0
1
2
3
4

This last loop could also have been written without the initialization and incrementation of i, using instead a block variable:

5.times do |i|
  p i
end

Our output is the same - block variables in times loops start with values of 0 and increase by 1 each time through the loop. To be clear, this is not the typical way of going about this - defining i outside of the loop is more common. Some text editors will try to be helpful and create block variables for you when you write a times loop (looking at you, Sublime), and the best thing to do is almost always to delete the block (hitting CMD + Z on macs is the easiest way - if you try to delete, it can cause a surprising amount of structural damage).

If a variable is defined outside of a loop and also as a block variable, the block variable will take precidence (that is, it will overwrite the old variable. That is:

i = 100

5.times do |i|
  p i
  i += 1
end

will output:

0
1
2
3
4

rather than:

100
101
102
103
104

Just for fun, let's look at an even less common example of a loop using a block variable:

2.upto(5) do |n|
  p n
end

The output is:

2
3
4
5

similar to the times loop but with more control over starting and ending values of the block variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment