Usando o método yield_self em Ruby

Dicas - 22/Mar/2020 - por André Kanamura

O método yield_self funciona de forma similar ao tap. Ambos são métodos comumente utilizados para executar blocos de ações sobre um mesmo objeto, mas, ao contrário do tap, o yield_self retorna o resultado da operação executada em vez do objeto. Vamos ver como isso funciona com um exemplo simples:

"hello".tap { |w| "#{w} world" }
 => "hello"

"hello".yield_self { |w| "#{w} world" }
 => "hello world"

Note como o tap retorna o objeto, modificado ou não pela ação executada no bloco. Já o yield_self retorna o resultado da operação. Isso pode ser útil quando estamos interessados somente na resposta que um objeto gera, mas não no objeto em si. Por exemplo, quando usamos a gem Faraday para intermediar o processo de requisição e resposta. Observe o código abaixo:

  def self.all
    url = 'http://localhost:3000/api/v1/product_types'
    response = Faraday.get(url)
    json = JSON.parse(response.body, symbolize_names: true)
    result = [ ]
    json.each do |item|
      result  << new(item[:id], item[:product_key])
    end
    return result
  end

Acima, definimos um método all dentro da classe Product para retornar a lista de todos os product_types (tipos de produtos) acessando a url de uma API e usamos Faraday para criar o objeto de resposta dessa requisição. Em seguida, lê-se o json gerado e é montado o array que compõe a resposta adequada. Usando o método yield_self, poderíamos escrever:

  def self.all
    url = 'http://localhost:3000/api/v1/product_types'
    result = [ ]
    url
      .yield_self { |url| Faraday.get(url) }.body
      .yield_self { |response| JSON.parse(response, symbolize_names: true) }
      .map { |item| result << new(item[:id], item[:product_key]) }
    return result
    end

Essa é uma possível aplicação para o método yield_self. Os ganhos em clareza de leitura ou em economia de linhas de código são discutíveis, mas certamente existem outras aplicações interessantes para esse método.

A partir da versão de Ruby 2.6, também está disponível o método then, que é sinônimo do yield_self.

"hello".then { |w| "#{ w } world" }
 => "hello world"

Referências

  • https://ruby-doc.org/core-2.7.0/Object.html#method-i-yield_self
  • https://www.assertnotmagic.com/2017/12/29/tap-and-yield-self/
  • https://zverok.github.io/blog/2018-01-24-yield_self.html
Foto de perfil do autor
André Kanamura

Dev na Campus Code