Можно ли смешивать модульный метод?

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

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

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

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

Это невозможно в Ruby?

Всего 1 ответ


Я хочу сделать это без изменения способа определения 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

Или с некоторой магией метапрограммирования, используя обратный вызов Ruby:

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.


Есть идеи?

10000