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?
Também me confundi no começo.
Ótimo artigo.
Æ!!
Tem uma variação do each que é o each_with_index:
[9,8,7,6,5,4,3,2,1].each_with_index do |number, index| do
puts “The index is #{index} and the numeber is #{number}”
end
;)
Há braços
Olá Thiago
Ótimo post!
Que plugin você usa para expor esses códigos?
Abraços!
Olá, ótimo artigo.
Só um detalhe: No exemplo do upto, o correto seria
1.upto(3) {|i| puts i}
e não
3.upto(1) {|i| puts i}
Abraço!
Pothix: É verdade. :)
Rodrigo, eu uso o SyntaxHighlighter: http://alexgorbatchev.com/wiki/SyntaxHighlighter
Rafael: Valeu pela correção. Consertei ali.
Hehe… Falando em ‘each’s, um metodo do Enumerable que descobri a pouco mto massa é o ‘.all?’
>> [1,2].all? { |x| x.kind_of? Numeric }
=> true
O que comecou a mostrar o poder do Ruby pra mim foram os ‘loops com funcionalidade’, ou seja, os iteradores tipo collect and inject que usam o o retorno do block:
[1, 2, 3].collect { |x| x + 1 } # => [2, 3, 4]
[1, 2, 3].inject { |result, x| result + x } # => 6
Sensacional…
Essa quantidade de loops também está me confundindo…
Mas esse post já deu uma esclarecida.