1. Technology
Send to a Friend via Email
You can opt-out at any time. Please refer to our privacy policy for contact information.

Loops

By

Ruby has more to offer than the typical 'for' and 'while' type loops. It even has more to offer than generics-style container iterators. Ruby has a very diverse and interesting collection of loops and loop methods.

First thing to note is that Ruby doesn't use the staple loop of most other programming langauges: the for loop. That isn't to say that Ruby doesn't have the for loop, because it does, but it's used so infrequently by Rubyists that it probably isn't worth learning. Instead, Ruby relies heavily on method-based loops more similar to an iterator for a collection than a loop. However, Ruby does have typical while/until loops and an infinite loop.

'Until' and 'While' Loops

While there are pennies in the jar, take a penny out of the jar. Until there are 100 jelly beans in the pile, eat a jelly bean. Both of these simple sentences are descriptions of loops: repeat something until a condition is met. And both of these describe the same loop. Both while and until loops do the same thing, but like 'if' and 'unless' the logic of their condition is reversed. The conditions themselves are simply boolean expressions.

The following is a typical while loop. There is a trick with the boolean expression though, the gets method returns nil if it fails to read a line, and nil is false. Also remember that the expression a = method_call() will evaluate to the value assigned to a.


#!/usr/bin/env ruby

File.open('data.txt') do|file|
  while line = file.gets
    line.chomp!
    
    # Print the third column of the line
    puts line.split(/ /)[2]
  end
end

Similarly, an until loop.


#!/usr/bin/env ruby

# 125 random jelly beans
beans = Array.new(125).map{rand}

# Eat beans until 100 are left
until beans.length == 100
  bean = beans.pop
  puts "Nom, nom, nom, tastes like #{bean}"
end

'While' and 'Until' as Modifiers

Just as with if and unless, Ruby has a shortcut if you're doing just a single statement inside the loop. As a bonus, it reads much better as well. Simply put while condition or until condition after the statement you want to repeat. For instance, if you wanted to remove elements from an array until the array's sum is less than 100, you could do the following:


array.pop until array.sum < 100

Or you could print a crude progress bar to the terminal until a download manager has finished downloading a file.


print '.' while download_manager.downloading?

Numeric Loops Without 'for'

In the introduction to this article, it was mentioned that Ruby has a for loop, but it isn't used. So how would you do something like the following C++ loop which counts from 1 to 100?


for( int i = 1; i <= 100; ++i) {
 // …
}

The short answer is: not with a loop. The long answer is: with an iterator method. Recall that methods in Ruby can take blocks as parameters. This is the main loop construct in Ruby, not the keyword loops. Ruby has a number of enumerable objects. To impement the above C loop in Ruby, what we really want to do is iterate over the range of numbers from 1 to 100. Simple, we'll use a Range object and use its each method to iterate over the numbers.


(1..100).each do|i|
  puts i
end

Why is the range in parentheses? Why not simply say 1..100.each? The .. operator doesn't bind very tightly, that would be equivalent to 1..(100.each), which would raise an exception because 100 doesn't have an each method. Parentheses must be used so the expression parses correctly.

But there's certainly more than one way to do it (but Ruby doesn't take this concept too far, that's Perl's bag). The Fixnum class has a number of methods for looping. Here, the upto method would be appropriate.


1.upto(100) do|i|
  puts i
end

And of course, there's a similar downto method.


100.downto(1) do|i|
  puts i
end

And, if you simply want to do something a certain number of times, there's the times method. This will print the message ten times, just to make sure the user gets the idea.


10.times do
  puts "WARNING: No chance to turn back!"
end

Container Iteration

To iterate over containers such as arrays and hashes (and any other enumerable objects), Ruby provides the each method. In languages like C, you often iterate over such collections by iterating over the indices of all their elements. However, Ruby is a bit more expressive than that. The following example iterates over each element of the array.


names = %w{ Alice Bob Carol }
names.each do|n|
  puts "Hello #{n}"
end

Infinite Loop

Once in a great while, you'll find yourself wanting an infinite loop. You can do something like an until false loop (which will loop forever because false will never be true), but Ruby has an infinite loop built in. It is simply the loop do loop.


loop do
  puts "This is the song that never ends!"
end

This loop will go on forever, or until broken by a break statement or an uncaught exception.

  1. About.com
  2. Technology
  3. Ruby
  4. Beginning Ruby
  5. Control Structures
  6. Loops

©2014 About.com. All rights reserved.