Можно ли смешивать модульный метод? - PullRequest
2 голосов
/ 16 января 2020

Допустим, у меня есть модуль, который объявляет метод модуля ( не метод экземпляра):

module M
  def self.foo
    puts 'foo'
  end
end

Теперь, допустим, я хочу добавить M.foo в другой класс C такой, что C.foo определен.

Наконец, я хочу сделать это без изменения способа определения M.foo и без создания метода в C, который вызывает M.foo. (т.е. перезапись foo как метода экземпляра не считается. Также не используется module_function.)

Разве это невозможно в Ruby?

1 Ответ

2 голосов
/ 16 января 2020

Я хочу сделать это без изменения способа определения M.foo

К сожалению, это невозможно. Ruby позволяет включать только модули, а не классы. Однако foo определяется для одноэлементного класса M, который является классом. Следовательно, вы не можете include это. То же ограничение распространяется на extend. Попытка сделать это приводит к TypeError:

module M
  def self.foo
    puts 'foo'
  end
end

class C
  extend M.singleton_class # TypeError: wrong argument type Class (expected Module)
end

Однако вы можете достичь желаемого, определив foo как метод экземпляра в отдельном модуле, который затем можно смешать в оба, M и C через extend: (этот модуль не обязательно должен быть вложен в M)

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods     # <- this makes foo available as M.foo
end

class C
  extend M::SingletonMethods  # <- this makes foo available as C.foo
end

Или с некоторыми метапрограммирующими волхвами c с использованием Ruby included обратный вызов:

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods

  def self.included(mod)
    mod.extend(SingletonMethods)
  end
end

class C
  include M
end

Это упрощенная версия того, как ActiveSupport::Concern работает в Rails.

...