Dando um tapa no rubí
Publicado em Developer
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) => 350Digamos 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
Comentários
Comentários fechados.
Artigos anteriores
- Pull requests em modo raiz - sex, 22 de dezembro de 2023, 09:57:09 -0300
- Qual a idade do seu repositório? - ter, 27 de dezembro de 2022, 12:50:35 -0300
- Utilizando ctags em projetos Rails mais recentes - qui, 24 de junho de 2021, 08:23:43 -0300
- Fazendo o seu projeto brotar - seg, 15 de julho de 2019, 08:57:05 -0300
- Learn Functional Programming with Elixir - sex, 02 de março de 2018, 18:47:13 -0300
- Ambiente mínimo - Driver Driven Development - qua, 23 de agosto de 2017, 15:15:03 -0300
- Ambiente mínimo - repositórios de código - dom, 16 de abril de 2017, 13:02:14 -0300
- Ambiente mínimo - terminal e navegador - dom, 02 de abril de 2017, 21:43:29 -0300
- Utilizando muitas gems no seu projeto? - sáb, 29 de outubro de 2016, 11:57:55 -0200
- Desenvolvedores e inteligência artificial - seg, 11 de julho de 2016, 09:09:38 -0300
Muito bom, substitui o feio obj.instance_eval{|obj| ...; obj}...