Back-End

27 mar, 2009

Dando um tapa no rubí

Publicidade

Vou comentar aqui um método novo encontrado no Ruby 1.9 chamado tap, que deu a inspiração para o título do artigo. O tap é um método que ajuda a verificar o que acontece com os objetos criados durante o uso de encadeamento de métodos, o que ajuda tanto em um sentido de debug como de encurtar um pouco o código escrito. Vejamos.

Vamos supor que tenho esse array:

palavras = %w(o doce perguntou para o doce que doce que era mais doce o doce 
falou para o doce que era o doce de batata doce)

Quero saber agora o seguinte: a relação de palavras que tem comprimento com mais de três caracteres e que terminam com a letra A. Nada difícil:

p palavras.select {|item| item.size>3}.select{|item| item =~ /a$/i}.uniq.sort

Só que fiquei curioso para saber quais foram as palavras que têm mais de três caracteres retornadas ali no primeiro select. Da maneira, digamos, convencional, posso fazer o seguinte:

temp = palavras.select {|item| item.size>3}
p temp.uniq.sort
p temp.select {|item| item =~ /a$/i}.uniq.sort
=> ["batata", "doce", "falou", "mais", "para", "perguntou"]
["batata", "para"]

Funcionou direitinho, mas vejam que eu tive que usar uma variável temporária, temp, para verificar quais foram as palavras com mais de três caracteres. O método tap
vai ser útil nesse ponto: inspecionar e interagir com o objeto corrente
encontrado entre os métodos encadeados. Vamos ver esse mesmo exemplo
usando tap:

p palavras.select {|item| item.size>3}.tap{|items| p items.uniq.sort}.
select{|item| item =~ /a$/i}.uniq.sort

Isso vai dar o mesmo resultado, com menos código se, nesse caso, quisermos resolver a nossa curiosidade. O tap
nos forneceu ali um “espião” para o objeto corrente. Um ponto
importante é que o valor retornado pelo bloco é o próprio objeto e não
a última expressão avaliada no bloco, e o objeto não muda a não ser que
se use um método destrutivo.

Vamos ver outro exemplo. Tenho o seguinte código:

a, b, c, d = 11, 1, 33, 2
puts (a-b)*(c+d)
=> 350

Digamos que o que rola ali é um cálculo mais complicado ou
estejamos naqueles dias ruins de matemática mesmo, mas queremos saber
por que o resultado deu 350. Podemos usar o tap para fazer isso:

puts (a-b).tap{|v| puts "esquerda: #{v}"} * (c+d).tap{|v| puts "direita : #{v}"}
esquerda: 10
direita : 35
350

Já dá uma ajudinha. E, para a turma que ainda não tem instalada alguma versão do Ruby 1.9, podemos alterar a classe Object (ê beleza, hein!) e criar o tap nas versões anteriores também:

class Object
def tap
yield self
self
end
end