Ruby: étendre le moi

113

Dans Ruby, je comprends l'idée de base de extend. Cependant, que se passe-t-il dans ce segment de code? Plus précisément, que fait extend-on? Est-ce juste un moyen pratique de transformer les méthodes d'instance en méthodes de classe? Pourquoi le feriez-vous de cette façon plutôt que de spécifier des méthodes de classe depuis le début?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end
Peter
la source

Réponses:

115

C'est un moyen pratique de transformer des méthodes d'instance en méthodes de classe. Mais vous pouvez également l'utiliser comme un singleton plus efficace .

cldwalker
la source
2
Pourquoi ce genre de singleton est-il plus efficace?
xuuso
5
Votre lien a pourri mon ami.
Ulysse BN
1
Mise à jour de cette réponse avec un lien vers archive.org
Mike Szyndel
1
Cette réponse est inadéquate car elle n'explique pas comment le mot-clé en question transforme les méthodes d'instance en méthodes de classe. Cela n'explique pas non plus ce qu'est un «singleton plus efficace», ni ce qui extend selfa à voir avec cela.
jayqui
29

Dans un module, self est la classe de module elle-même. Donc par exemple

puts self

retournera Rake donc,

extend self

met essentiellement à sa disposition les méthodes d'instance définies dans Rake, vous pouvez donc faire

Rake.run_tests
ennuikiller
la source
23

Pour moi, il est toujours utile de penser extendàinclude à l' intérieur de la classe singleton (également connu sous le nom de méta ou classe eigen).

Vous savez probablement que les méthodes définies dans la classe singleton sont essentiellement des méthodes de classe:

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

A.x #=> 'x'

Maintenant que nous savons que, extendseront includeles méthodes dans le module intérieur de la classe singleton et donc les exposer comme des méthodes 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'
fphilipe
la source
15

Pour éviter la pourriture des liens, le billet de blog de Chris Wanstrath lié par user83510 est republié ci-dessous (avec sa permission). Pourtant, rien ne vaut un original, alors utilisez son lien aussi longtemps qu'il continue de fonctionner.


→ Singin 'singletons 18 novembre 2008 Il y a des choses que je ne comprends pas. David Bowie, par exemple. Ou l'hémisphère sud. Mais rien ne me dérange autant que Ruby's Singleton. Parce que vraiment, c'est totalement inutile.

Voici ce qu'ils veulent que vous fassiez avec votre code:

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'

Mais c'est fou. Combattre le pouvoir.

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'

Pourquoi pas? L'API est plus concise, le code est plus facile à tester, simuler et stub, et il est toujours très simple de le convertir en une classe appropriée en cas de besoin.

((le droit d'auteur devrait dix chris wanstrath))

forforf
la source
Une autre façon d'éviter linkrot est d'utiliser quelque chose comme la machine de retour - web.archive.org - elle garde un historique des pages sur le Web, je l'ai trouvé très utile dans de nombreux cas de linkrot de toute façon.
Kem Mason
3

extend selfinclut toutes les méthodes d'instance existantes en tant que méthodes de module. Cela équivaut à dire extend Rake. Est aussi Rakeun objet de classe Module.

Une autre façon d'obtenir un comportement équivalent sera:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Cela peut être utilisé pour définir des modules autonomes avec des méthodes privées.

Sulabh Jain
la source