Ruby: rozszerz siebie

113

W Rubim rozumiem podstawową ideę extend. Jednak co się dzieje w tym segmencie kodu? A konkretnie, co robi extend? Czy jest to tylko wygodny sposób przekształcenia metod instancji w metody klasowe? Dlaczego miałbyś to robić w ten sposób, zamiast określać metody klas od początku?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end
Piotr
źródło

Odpowiedzi:

115

Jest to wygodny sposób przekształcania metod instancji w metody klasowe. Ale możesz też użyć go jako bardziej wydajnego singletona .

cldwalker
źródło
2
Dlaczego taki singleton jest bardziej wydajny?
xuuso
5
Twój link zgnił mojego przyjaciela.
Ulysse BN,
1
Zaktualizowałem tę odpowiedź linkiem do archive.org
Mike Szyndel
1
Ta odpowiedź jest niewystarczająca, ponieważ nie wyjaśnia, w jaki sposób dane słowo kluczowe przekształca metody instancji w metody klas. Nie wyjaśnia też, czym jest „bardziej wydajny singleton” ani co extend selfma z tym wspólnego.
jayqui
29

W module self jest samą klasą modułu. Na przykład

puts self

zwróci Rake, więc

extend self

zasadniczo udostępnia metody instancji zdefiniowane w Rake, więc możesz to zrobić

Rake.run_tests
ennuikiller
źródło
23

Dla mnie to zawsze pomaga myśleć extendjak includewewnątrz klasy singleton (znany również jako meta lub EIGEN klasie).

Zapewne wiesz, że metody zdefiniowane w klasie singleton są w zasadzie metodami klasowymi:

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

A.x #=> 'x'

Teraz, gdy wiemy, że extendbędą includemetody w module wewnątrz klasy singleton, a tym samym narazić je jako metody klasy:

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
źródło
15

Aby uniknąć gnicia linków, poniżej opublikowano ponownie post Chrisa Wanstratha, do którego prowadzi user83510 (za jego zgodą). Jednak nic nie przebije oryginału, więc używaj jego linku tak długo, jak będzie działać.


→ singin 'singletons 18 listopada 2008 Są rzeczy, których po prostu nie rozumiem. Na przykład David Bowie. Albo na półkuli południowej. Ale nic tak nie zadziwia mnie jak Singleton Ruby. Bo naprawdę, to zupełnie niepotrzebne.

Oto, co chcą, abyś zrobił ze swoim kodem:

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'

Ale to jest szalone. Walcz z mocą.

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'

Każdy, dlaczego nie? Interfejs API jest bardziej zwięzły, kod jest łatwiejszy do testowania, makiety i odgałęzienia, a konwersja na odpowiednią klasę w razie potrzeby jest nadal bardzo prosta.

((prawa autorskie powinny mieć ten Chris Wanstrath))

forforf
źródło
Innym sposobem uniknięcia linkrot jest użycie czegoś w rodzaju wayback machine - web.archive.org - przechowuje historię stron w sieci, i tak uznałem to za bardzo pomocne w wielu przypadkach linkrot.
Kem Mason
3

extend selfobejmuje wszystkie istniejące metody instancji jako metody modułu. To jest równoznaczne z powiedzeniem extend Rake. Również Rakejest obiektem klasy Module.

Innym sposobem uzyskania równoważnego zachowania będzie:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Może to służyć do definiowania samodzielnych modułów z prywatnymi metodami.

Sulabh Jain
źródło