Как получить доступ к модулю из метода экземпляра в Ruby?

Предположим, у меня есть модуль:

module M
  def self.foo
    ...
  end

  def bar
    ...
  end
end

модуль M входит в класс.

class A
  include M
end

Я хочу позвонить foo от bar, который в конечном итоге будет вызван на экземпляр A, Какой лучший способ сделать это внутри bar?

Конечно я могу просто сказать M.foo, но это дублирование имени модуля, которое кажется ненужным.

3 ответа

Решение

Обычно в module Хорошей практикой является разделение методов класса и методов экземпляра следующим образом:

module M
  def bar
    puts "BAR"
    self.class.foo
  end

  module ClassMethods
    def foo
      puts "FOO"
    end
  end
end

Теперь, в классе, я бы идеально хотел include этот модуль M таким образом, что я получаю A.foo как метод класса и A.new.bar как метод экземпляра. Трюк для этого Module.included,

module M
  def bar
    puts "BAR"
    self.class.foo
  end

  module ClassMethods
    def foo
      puts "FOO"
    end
  end

  # when module is included, extend the class with ClassMethods
  def self.included(base)
    base.extend ClassMethods
  end
end

class A
  include M
end

A.singleton_methods #=> [:foo]

A.new.foo
#=> BAR
#=> FOO

При таком подходе вы можете ссылаться на метод класса с self.class и это будет работать автоматически.

Надеюсь, поможет.

Я думаю, используя M.foo лучше, но в качестве упражнения можно изменить M#bar следующее.

module M
  def self.foo
    puts "In self.foo"
  end

  def bar
    puts "In bar"
    method(__method__).owner.foo
  end
end

class A
  include M
end

a = A.new
a.bar
  # In bar
  # In self.foo

Не очень элегантно, но

def bar
  Module.nesting.last.foo
end

должен сделать это.

Обратите внимание, что Module#nesting возвращает массив, потому что один модуль может быть вложен в другой модуль. В общем случае вам нужно применить правильный индекс массива, чтобы выбрать модуль, который вы хотите иметь.

Другие вопросы по тегам