Uma das coisas que mais me confundiu a cabeça quando comecei a aprender Ruby foram os loops. Vindo de Java e C, não me entrava na cabeça como uma coisa simples como um loop poderia ser escrito de tantas maneiras diferentes. Isso simplesmente não parecia certo pra mim. Passado um bom tempo, comecei a compreender essa liberdade dada ao programador e a creditar isso ao poder e dinamicidade do Ruby.

Por curiosidade, resolvi tentar descobri todas as maneiras possíveis de se executar um loop com Ruby, e tentarei lista-las aqui.

While

Loops do tipo While no Ruby são exatamente iguais aos encontrados em Java, C# e outros. Um bloco deve ser executado enquanto uma condição for verdadeira.

x = 1
while(x <4)
	puts x
	x +=1
end

=> 1
   2
   3

O while também pode ser usado ao final de um bloco, de maneira semelhando ao “DO…WHILE” de outras linguagens.

x =1
begin
	puts x
	x+=1
end while (x<4)

=> 1
   2
   3

Irmão inverso do while, o until executa um bloco de código até que uma condição seja verdadeira.

x = 1
until(x>3)
  puts x
  x +=1
end

=> 1
   2
   3

E, como no while, também pode ser usado como condição de execução ao fim de um bloco.

x = 1
begin
  puts x
  x+=1
end until (x>3)

=> 1
   2
   3

For

Outro loop clássico das linguagens, o for assume algumas particularidades no Ruby. Os ranges de Ruby podem ser usados em um for. Tanto na versão “intervalo aberto e fechado”.

#Intervalo aberto
for i in 1..3
  puts i
end

=> 1
   2
   3
#Intervalo fechado
for i in 1...4
  puts i
end

=> 1
   2
   3

Além disso, podemos iterar sobre letra do alfabeto, como no exemplo abaixo:

for x in 'a'..'d'
  puts x
end

=> a
   b
   c
   d

Iteradores

O iterator, é um padrão de projeto que nos permite percorrer objetos agregados sem que sua verdadeira relação com o grupo ao qual pertence seja exposto. Ruby já fornece o padrão iterator através do método each.

[1,2,3].each do |i|
  puts i
end

=> 1
   2
   3

Que também pode ser usado com ranges:

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

=> 1
   2
   3

Métodos da Classe Fixnum

As opções não param nas citadas acima. Ainda temos alguns métodos da flasse Fixnum que nos fornecem comportamentos semelhante aos loops clássicos.

O método Fixnum#times recebe um bloco como parâmetro, e o executa o mesmo número de vezes do objeto Fixnum que o executou.

i = 1
3.times do
  puts i
  i+=1
end

=> 1
   2
   3

Temos também os métodos upto e downto que, como o times, também recebe um bloco e o executa, porém com um objeto de índice do bloco.

1.upto(3) {|i| puts i}

=> 1
   2
   3

3.downto(1) {|i| puts i}

=> 3
   2
   1

Outras Esquisitices

Em Ruby também temos um loop infinito, semelhante a um while(true), que deve ser quebrado mediante alguma condição definida dentro do bloco de execução. Um exemplo prático poderia ser uma verificação de senha via linha de comando:

loop do
  puts "Enter your password"
  gets
  chomp
  break if $_ =="123"
  puts "WRONG! Try again!"
end

E por fim, algumas malandragens típicas do Ruby. Como eu usei o mesmo exemplo em todo esse post, aqui vão algumas outras maneiras de imprimir na tela os números:

puts (1..3).to_a* "\n"

puts (1..3).to_a

puts *(1..3)

puts 1,2,3

Será que eu me esqueci de algum?