Ruby: estenda-se


113

Em Ruby, eu entendo a ideia básica de extend. No entanto, o que está acontecendo neste segmento de código? Especificamente, o que extendfaz? É apenas uma maneira conveniente de transformar os métodos de instância em métodos de classe? Por que você faria dessa maneira em vez de especificar métodos de classe desde o início?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end

Respostas:


115

É uma maneira conveniente de transformar métodos de instância em métodos de classe. Mas você também pode usá-lo como um singleton mais eficiente .


2
Por que esse tipo de singleton é mais eficiente?
xuuso

5
Seu link estragou meu amigo.
Ulysse BN

1
Esta resposta foi atualizada com um link para archive.org
Mike Szyndel

1
Essa resposta é inadequada porque não explica como a palavra-chave em questão transforma métodos de instância em métodos de classe. Também não explica o que é um 'singleton mais eficiente' ou o que extend selftem a ver com isso.
Jayqui

29

Em um módulo, self é a própria classe do módulo. Então por exemplo

puts self

irá devolver o Rake,

extend self

basicamente torna os métodos de instância definidos no Rake disponíveis para ele, para que você possa fazer

Rake.run_tests

23

Para mim, sempre ajuda pensar extendque está includedentro da classe singleton (também conhecida como classe meta ou eigen).

Você provavelmente sabe que os métodos definidos dentro da classe singleton são basicamente métodos de classe:

module A
  class << self
    def x
      puts 'x'
    end
  end
end

A.x #=> 'x'

Agora que sabemos que, extendse includeos métodos no módulo dentro da classe singleton e, portanto, expô-los como métodos de classe:

module A
  class << self
    include A

    def x
      puts 'x'
    end
  end

  def y
    puts 'y'
  end
end

A.x #=> 'x'
A.y #=> 'y'

15

Para evitar o apodrecimento do link, a postagem do blog de Chris Wanstrath com o link do usuário 83510 é postada novamente abaixo (com sua permissão). Ainda assim, nada supera um original, então use seu link enquanto ele continuar funcionando.


→ singletons cantando 18 de novembro de 2008 Há coisas que eu simplesmente não entendo. David Bowie, por exemplo. Ou o hemisfério sul. Mas nada confunde minha mente como o Singleton de Ruby. Porque realmente, é totalmente desnecessário.

Aqui está o que eles querem que você faça com seu código:

require 'net/http'

# first you setup your singleton
class Cheat
  include Singleton

  def initialize
    @host = 'http://cheat.errtheblog.com/'
    @http = Net::HTTP.start(URI.parse(@host).host)
  end


  def sheet(name)
    @http.get("/s/#{name}").body
  end
end

# then you use it
Cheat.instance.sheet 'migrations'
Cheat.instance.sheet 'yahoo_ceo'

Mas isso é loucura. Combate o Poder.

require 'net/http'

# here's how we roll
module Cheat
  extend self

  def host
    @host ||= 'http://cheat.errtheblog.com/'
  end

  def http
    @http ||= Net::HTTP.start(URI.parse(host).host)
  end

  def sheet(name)
    http.get("/s/#{name}").body
  end
end

# then you use it
Cheat.sheet 'migrations'
Cheat.sheet 'singletons'

Qualquer por que não? A API é mais concisa, o código é mais fácil de testar, simular e stub, e ainda é muito simples de converter em uma classe adequada, caso haja necessidade.

((copyright ought ten chris wanstrath))


Outra forma de evitar o linkrot é usar algo como a máquina de retorno - web.archive.org - ela mantém um histórico de páginas na web, achei bastante útil em muitos casos de linkrot de qualquer maneira.
Kem Mason

3

extend selfinclui todos os métodos de instância existentes como métodos de módulo. Isso é equivalente a dizer extend Rake. Também Rakeé um objeto de classe Module.

Outra maneira de obter um comportamento equivalente será:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Isso pode ser usado para definir módulos independentes com métodos privados.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.