Ruby: extender uno mismo

113

En Ruby, entiendo la idea básica de extend. Sin embargo, ¿qué está pasando en este segmento de código? Específicamente, ¿qué hace extend? ¿Es solo una forma conveniente de convertir los métodos de instancia en métodos de clase? ¿Por qué lo haría de esta manera en lugar de especificar métodos de clase desde el principio?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end
Pedro
fuente

Respuestas:

115

Es una forma conveniente de convertir métodos de instancia en métodos de clase. Pero también puede usarlo como un singleton más eficiente .

cldwalker
fuente
2
¿Por qué ese tipo de singleton es más eficiente?
xuuso
5
Tu enlace ha podrido a mi amigo.
Ulysse BN
1
Se actualizó esta respuesta con un enlace a archive.org
Mike Szyndel
1
Esta respuesta es inadecuada porque no explica cómo la palabra clave en cuestión convierte los métodos de instancia en métodos de clase. Tampoco explica qué es un "singleton más eficiente", o qué extend selftiene que ver con eso.
jayqui
29

En un módulo, self es la propia clase del módulo. Así por ejemplo

puts self

volverá Rake así,

extend self

básicamente hace que los métodos de instancia definidos en Rake estén disponibles para él, por lo que puede hacer

Rake.run_tests
ennuikiller
fuente
23

Para mí, siempre es útil pensar extendque está includedentro de la clase singleton (también conocida como meta o clase propia).

Probablemente sepa que los métodos definidos dentro de la clase singleton son básicamente métodos de clase:

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

A.x #=> 'x'

Ahora que sabemos eso, los métodos en el módulo extendestarán includedentro de la clase singleton y así los expondrán como métodos de clase:

module A
  class << self
    include A

    def x
      puts 'x'
    end
  end

  def y
    puts 'y'
  end
end

A.x #=> 'x'
A.y #=> 'y'
fphilipe
fuente
15

Para evitar que el enlace se pudra, la publicación del blog de Chris Wanstrath vinculada por user83510 se vuelve a publicar a continuación (con su permiso). Aún así, nada supera a un original, así que use su enlace mientras siga funcionando.


→ singin 'singletons 18 de noviembre de 2008 Hay cosas que simplemente no entiendo. David Bowie, por ejemplo. O el hemisferio sur. Pero nada me aturde tanto como Ruby's Singleton. Porque en realidad es totalmente innecesario.

Esto es lo que quieren que hagas con tu 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'

Pero eso es una locura. Luchar contra el 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'

Cualquiera, ¿por qué no? La API es más concisa, el código es más fácil de probar, simular y apuntar, y todavía es muy simple de convertir en una clase adecuada si surge la necesidad.

((el derecho de autor debe diez chris wanstrath))

forforf
fuente
Otra forma de evitar el linkrot es usar algo como la máquina wayback - web.archive.org - mantiene un historial de páginas en la web, lo he encontrado bastante útil en muchos casos de linkrot de todos modos.
Kem Mason
3

extend selfincluye todos los métodos de instancia existentes como métodos de módulo. Esto equivale a decir extend Rake. También Rakees un objeto de clase Module.

Otra forma de lograr un comportamiento equivalente será:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Esto se puede utilizar para definir módulos autónomos con métodos privados.

Sulabh Jain
fuente