Ruby: расширить себя


113

В Ruby я понимаю основную идею extend. Однако что происходит в этом сегменте кода? В частности, что делает extend? Это просто удобный способ превратить методы экземпляра в методы класса? Почему бы вам сделать это именно так, вместо того, чтобы указывать методы класса с самого начала?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end

Ответы:


115

Это удобный способ превратить методы экземпляра в методы класса. Но вы также можете использовать его как более эффективный синглтон .


2
Почему такой синглтон более эффективен?
xuuso

5
Твоя ссылка прогнила мой друг.
Ulysse BN

1
Обновил этот ответ ссылкой на archive.org
Майк Шиндел

1
Этот ответ неадекватен, потому что он не объясняет, как ключевое слово, о котором идет речь, превращает методы экземпляра в методы класса. Он также не объясняет, что такое «более эффективный синглтон» и что extend selfс этим связано.
jayqui

29

В модуле self - это сам класс модуля. Так например

puts self

вернет грабли так,

extend self

в основном делает доступными методы экземпляра, определенные в Rake, так что вы можете делать

Rake.run_tests

23

Мне всегда помогает думать о том, extendчто includeвнутри класса singleton (также известный как мета или собственный класс).

Вы, наверное, знаете, что методы, определенные внутри класса singleton, в основном являются методами класса:

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

A.x #=> 'x'

Теперь, когда мы это знаем, extendбудут includeли методы в модуле внутри одноэлементного класса и, таким образом, открывать их как методы класса:

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

Чтобы избежать гниения ссылок, ниже публикуется сообщение в блоге Криса Ванстрата, на которое ссылается user83510 (с его разрешения). Тем не менее, ничто не сравнится с оригиналом, поэтому используйте его ссылку, пока она продолжает работать.


→ singletons 18 ноября 2008 Есть вещи, которых я просто не понимаю. Дэвид Боуи, например. Или Южное полушарие. Но ничто так не поражает меня, как синглтон Руби. Потому что на самом деле это совершенно не нужно.

Вот что они хотят, чтобы вы делали со своим кодом:

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'

Но это безумие. Бороться с властью.

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'

А почему бы и нет? API более лаконичен, код легче тестировать, имитировать и создавать заглушки, и его все еще очень просто преобразовать в подходящий класс, если возникнет такая необходимость.

((авторское право должно быть десять Крис Ванстрат))


Другой способ избежать ротации ссылок - это использовать что-то вроде машины обратного пути - web.archive.org - она ​​хранит историю страниц в сети, и я считаю ее весьма полезной во многих случаях ротации ссылок.
Кем Мейсон

3

extend selfвключает все существующие методы экземпляра как методы модуля. Это эквивалентно высказыванию extend Rake. Также Rakeявляется объектом класса Module.

Другой способ добиться эквивалентного поведения:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Это можно использовать для определения автономных модулей с частными методами.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.