2
respostas

Convertendo um Symbol em uma Proc?

Ola,

Eu tenho 3 duvidas em relacao ao codigo a baixo:

1 - O que seria o operador & em quantity_sold_by(b1, &:title)? Eu entendo que o :title no caso eh um Symbol ou a key do objeto book.

2 - O que me permite realizar a seguinte chamada field.call(book)? E como eu poderia ler isso?

3 - Eu tentei alterar o codigo pra ver se conseguiria o mesmo resultado de outra maneira como book.field ou book[:field], mas em muitos casos notei erros associados com #<Proc:0x0000562d55506198(&:title)>

 def quantity_sold_by(book, &field)
    @sales.count {
      |e| field.call(e) == field.call(book)
    }
  end

  def most_sold_book_by_title
    @sales.sort {
      |b1, b2| quantity_sold_by(b1, &:title) <=> quantity_sold_by(b2, &:title)
    }.last
  end
2 respostas

Ola,

Alguma atualizacao em relacao a minha duvida?

Oi, Bruno, eu não sei muito sobre o código criado no curso mas vou tentar me basear no seu código tudo bem?

1 - Quando você usa o quantity_sold_by(b1, &:title) o & é equivalente a chamar to_proc então o que está acontecendo é estamos criando uma expressão vai chamar o método :title no futuro. (Os métodos em Ruby são guardados como symbols). Um exemplo:

$ irb
2.7.1 :001 > class Produto
2.7.1 :002 >   def teste_proc
2.7.1 :003 >     puts 'testeeeeeeeeeeeeee'
2.7.1 :004 >   end
2.7.1 :005 > end
 => :teste_proc
2.7.1 :006 > :teste_proc.to_proc
 => #<Proc:0x0000563a36c4e958(&:teste_proc)>

Essa é a implementação do Ruby para closures. Uma Proc / Lambda é um objeto que guarda um bloco de código.

2 - Agora que salvamos esse método numa Proc, toda Proc responde ao método call para executar o bloco de código que está lá dentro.

2.7.1 :007 > proc = :teste_proc.to_proc
2.7.1 :008 > proc.call
ArgumentError (no receiver given)

Como você pode ver pelo erro a Proc também precisa de um receiver que vai ser em que objeto vamos chamar esse pedaço de código que guardamos nela no meu caso vou chamar numa instancia de Produto que era quem implementava esse método.

2.7.1 :009 > proc = :teste_proc.to_proc
 2.7.1 :010 > proc.call(Produto.new)
testeeeeeeeeeeeeee

Agora o Ruby executou o método guardado na Proc teste_proc em cima do objeto que eu pedi Produto.new e tudo deu certo.

3 - Por último falando sobre o &field você tá avisando ao Ruby que o pedaço de código que vai enviar é um bloco no nosso caso enviamos a Proc para frente para ser executada.

São operadores bem complexos não sei se sanei todas as dúvidas mas você pode ler mais na documentação da Proc. Indico bastante também esse artigo (um pouco velho hoje em dia) mas ainda relevante que passa pelos passos do que o Ruby vê quando percebe um & no seu código.