valor:
a = b = c = 0
p a, b, c # => 0 0 0
Até mesmo quando utilizamos um for, o seu resultado é uma expressão. Se
percorrermos um Array com três elementos usando um for e multiplicarmos
cada item por 2, por exemplo, podemos atribuir seu resultado a uma variável:
numeros = [1, 2, 3, 4]
novos_numeros = for n in numeros
n * 2
end
p novos_numeros # => [1, 2, 3, 4]
O método for que utilizamos retorna um Array com os mesmos valores in-
seridos no Array antigo. Esse é o comportamento do for e também do método
each que veremos em breve, retornar sempre o Array original. Para criar um novo
Array com os valores retornados por cada iteração é necessário utilizar o método
map que também será visto em breve.
Métodos sem return
Todos os métodos Ruby retornam sempre o resultado da última expressão de-
clarada, por esse motivo, você não precisa explicitamente adicionar o return no
final de cada método:
def boas_vindas(nome)
"Bem vindo: #{nome}"
end
p boas_vindas("Lucas") # => "Bem vindo: Lucas"
Quando invocado o método boas_vindas retornará a String interpolada
com o valor do argumento nome que foi passado.
68
Casa do Código
Capítulo 5. Ruby e a programação funcional
5.4
Funções de alta ordem Higher-order functions
Funções ou métodos são high-order quando tem a capacidade de receber outras fun-
ções como argumentos ou retornar funções como resultado. Em Ruby isto é feito
usando blocos, lambdas e procs.
Blocos, lambdas e procs são um dos aspectos mais poderoso da linguagem Ruby,
e também um dos que causam mais confusões para serem entendidos, isso porque
Ruby possui quatro maneiras de lidar com high-order functions.
Blocos
Este é o método mais comum trabalhar com funções high-order em Ruby. Os
blocos são muito utilizados e comuns quando percorremos coleções:
numeros = [1, 2, 3, 4]
numeros.each { |numero| p numero }
# => 1
# => 2
# => 3
# => 4
Mas o que está acontecendo nesse código afinal?
A primeira e mais importante parte que devemos entender, está na chamada ao
método each que fizemos na variável numeros. Ao invocarmos o método, estamos
passando uma
função ou bloco de código como argumento. Internamente o método
each itera o Array, executa o bloco de código recebido como argumento passando
o valor da iteração (neste caso a variável numero). O bloco de código que recebe a
variável numero está imprimindo a mesma no console utilizando o método p.
Existem outros métodos da classe Array que recebem um bloco de código como
argumento e o executam a cada iteração. Por exemplo, o método collect:
numeros = [1, 2, 3, 4]
numeros_ao_quadrado = numeros.collect { |numero| numero ** 2 }
p numeros_ao_quadrado # => [1, 4, 9, 16]
O comportamento do método collect é similar ao método each, cada item
do Array onde o método foi invocado é passado como argumento para o bloco
recebido na chamada.
69
5.5. Crie seu próprio código que usa um bloco de código
Casa do Código
Ao invocar o método
collect obtemos um novo
Array com todos
os números ao quadrado.
Desta maneira, quando imprimimos a variável
numeros_ao_quadrado o resultado é [1, 4, 9, 16].
Tanto o método each quanto o método collect fazem parte da API pública da
classe Array. Existem vários outros método bastante úteis na API dos arrays, você
deve sempre consultá-la para não reimplementar comportamentos que já existem.
Lembre-se que um dos principais atrativos da linguagem Ruby é a sua legibilidade,
conhecer bem a API da linguagem é um dos passos mais importantes para conseguir
tal vantagem.
5.5
Crie seu próprio código que usa um bloco de có-
digo
Mas e se quisermos criar nosso próprio método que recebe um bloco de código?
Como podemos implementá-lo?
Vamos criar um método que filtra os livros por uma determinada categoria, itera
cada um destes livros e executa um bloco de código que será passado para este mé-
todo. Nosso primeiro passo será criar o método dentro da classe Biblioteca:
class Biblioteca
def initialize
@livros = {} # Inicializa com um hash
end
def adiciona(livro)
@livros[livro.categoria] ||= []
@livros[livro.categoria] << livro
end
def livros
@livros.values.flatten
end
def livros_por_categoria(categoria)
@livros[categoria]
end
end
O filtro por categoria é bem simples, o argumento esperado será o Symbol
70
Casa do Código
Capítulo 5. Ruby e a programação funcional
identificador do tipo dos livros que desejamos. Agora precisamos iterar estes livros
e executar um bloco de código passado como argumento na chamada do método
livros_por_categoria:
class Biblioteca
def initialize
@livros = {} # Inicializa com um hash
end
def adiciona(livro)
@livros[livro.categoria] ||= []
@livros[livro.categoria] << livro
end
def livros
@livros.values.flaten
end
def livros_por_categoria(categoria)
@livros[categoria].each do |livro|
yield livro
end
end
end
Quando filtramos os livros por categoria: @livros[categoria], recebemos
como retorno um Array, e agora podemos percorrê-lo utilizando o método each