Taq

Eustáquio Rangel

Desenvolvedor, pai, metalhead

Dando um tapa no rubí

Publicado em Developer

Lupa

Vou comentar aqui um método novo encontrado no Ruby 1.9 (que mais tarde vou mostrar como é fácil de por no 1.8) chamado tap, que deu a inspiração para o título do post, influenciado pelo cômico Tapa na Pantera.

O que o tap faz é meio diferente do sentido da pantera quieta e sendo cutucada para despertar. Nesse caso, a pantera já está em movimento mas a gente quer saber exatamente o que está acontecendo nas entranhas dela (argh!). Falando um pouco mais seriamente, seria um método que ajuda em 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 3 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 tem mais de 3 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 3 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 porque 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

Tags:




Comentários

comments powered by Disqus