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.