Рубин: расширьте себя

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

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end

Ответ 1

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

Ответ 2

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

puts self

вернется Рейк поэтому

extend self

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

Rake.run_tests

Ответ 3

Для меня всегда полезно думать о extend как include внутри одноэлементного класса (также известного как мета или собственный класс).

Вероятно, вы знаете, что методы, определенные внутри класса 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'

Ответ 4

Чтобы избежать гниения ссылок, сообщение

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

require 'net/http'

# here 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 более краткий, код легче тестировать, издеваться и заглушать, а его все еще мертвый просто преобразовать в правильный класс, если возникнет необходимость.

((авторское право должно быть десять chris wanstrath))

Ответ 5

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

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

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

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