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