o bloco, mas ainda assim precisamos respeitar o número de parâmetros. Podemos
assim usar o _, que irá absorver esse parâmetro sem ter a necessidade de ter que
declarar uma nova variável:
a = {:a => 1, :b => 2, :c => 3}
a.each do |_, value|
puts value
end # 1; 2; 3
É recomendado sempre usar o _ ao invés de simplesmente omitir os valores. Al-
gumas vezes é possível simplesmente omitir, porém existem métodos cujo compor-
tamento muda de acordo com o número de parâmetros passados (conhecido como
38
Casa do Código
Capítulo 2. Conhecendo Ruby
arity). Isso acontece porque é possível verificar quantos parâmetros o bloco pode
receber:
a = {:a => 1, :b => 2, :c => 3}
a.each do |key|
puts key
end
# a
# 1
# b
# 2
# c
# 3
Controle de fluxo em blocos
No caso de uso de blocos como iteradores, é possível controlar o fluxo com al-
gumas expressões. Existem várias que raramente são usadas. As principais são as
seguintes:
break - Pára o iterador completamente no momento em que for chamado;
next - Passa para o próximo elemento;
Vejamos alguns exemplos:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.each do |number|
next if number.odd?
puts number
end # 2; 4; 6; 8; 10
numbers.each do |number|
break if number > 5
puts number
end # 1; 2; 3; 4; 5
2.5
Funções, blocos, lambdas e closure
Em Ruby, declarações de funções e métodos são assim:
39
2.5. Funções, blocos, lambdas e closure
Casa do Código
def print_text(text)
puts text
end
# É possível omitir os parênteses
def print_text text, more_text
puts text + more_text
end
Retorno de métodos e funções
Diferente da maioria das linguagens, em Ruby não é necessário colocar um
return para retornar um valor, porque o último código executado de um método
será o objeto retornado:
def double_that(number)
var = "isso não é relevante"
number * number
end
puts double_that(10) # 100
Lembrando que a maioria dos blocos de código Ruby retornam valor, tal como
o próprio if (seção 2.4). Portanto, é possível construir funções da seguinte maneira:
def am_i_rich?(cash)
if cash > 1_000_000
"sim"
else
"não"
end
end
puts am_i_rich?(100) # "não"
Às vezes, porém, é interessante retornar em um ponto específico da função.
Dessa forma, usamos o return:
def factorial(n)
return 1 if n == 1
n * factorial(n-1)
40
Casa do Código
Capítulo 2. Conhecendo Ruby
end
factorial(1) # 1
factorial(3) # 6
No exemplo
anterior, no caso em que n é 1, a função retorna 1, sem executar o
trecho na linha 4.
return e blocos
Cuidado com o uso de return dentro de blocos. Primeiro porque não
existe um comportamento intuitivo para o return de dentro de blocos.
Ele deve encerrar o loop, tal como o break? Ele deve ceder o fluxo de volta
para o método original, tal como o next? Nenhum dos dois. Ele de fato
não tem nenhum comportamento especial com blocos, ou seja, o return
termina a execução do método/função a qual o bloco está associado.
A segunda razão para não fazer isso é que, se houver um código im-
portante que precisa ser executado posterior ao bloco, como no caso do
File.open, ele deixará de ser executado.
alias
É possível criar múltiplos nomes para uma função via a expressão alias:
def factorial(n)
return 1 if n == 1
n * factorial(n-1)
end
alias fac factorial
fac(5) # 120
Esta possibilidade pode parecer meio inútil a princípio, mas, em diversas situa-
ções, torna a linguagem mais expressiva e natural, ou seja, a leitura de código Ruby
tende a ser bem próxima do inglês. Dessa forma, criam-se aliases para funções de
forma a melhorar a legibilidade do código produzido. O exemplo a seguir é usado
no próprio Rails:
41
2.5. Funções, blocos, lambdas e closure
Casa do Código
require 'active_support/all'
1.hour.ago
# 2012-04-30 20:15:26 -0300
# Leitura péssima, mas funciona
2.hour.ago
# 2012-04-30 19:15:26 -0300
# Agora faz sentido!
2.hours.ago
# 2012-04-30 19:15:26 -0300
Parâmetros default
É possível criar funções e métodos com parâmetros padrão usando a seguinte
sintaxe:
def truncate(string, length=20)
string[0,length-3] + "..."
end
puts truncate("Truncando essa linha longa")
# Truncando essa li...
puts truncate("Truncando essa linha longa", 10) # Truncan...
Números de argumentos variáveis
Em Ruby podemos criar métodos que aceitam um número variado de argumen-
tos. Conseguimos isso através do uso do operador splat:
def sum(*values)
puts values.inspect
values.reduce { |sum, value| sum + value }
end
sum(1)
# [1]; 1
sum(1, 1)
# [1,1]; 2
sum(1, 2, 3, 4, 10) # [1, 2, 3, 4, 10]; 20
É possível destacar alguns parâmetros caso isso seja interessante:
def sum(first, *values)
puts values.inspect
42
Casa do Código
Capítulo 2. Conhecendo Ruby
values.reduce(first) { |sum, value| sum + value }
end
sum(1)
# []; 1
sum(1, 1)
# [1]; 2
sum(1, 2, 3, 4, 10) # [2, 3, 4, 10]; 20
Hashes para parâmetros nomeados
Alguns métodos podem precisar receber muitos parâmetros. Agora, imagine
uma chamada de método dessa forma: process(1, 10, friends, Date.today,