Ruby выполняет self.included(базовый) метод на подклассах без явного включения объявления?

125
13

У меня есть несколько классов, которые наследуются от одного суперкласса.
Суперкласс как определенный модуль. Внутри модуля используется метод self.included(base), который устанавливает некоторые переменные экземпляра.


Так что-то вроде этого:


module MyModule
def self.included(base)
base.instance_variable_set("@my_instance_variable", {})
end
end

class MySuperClass
include MyModule
end

class ClassA < MySuperClass
end

class ClassB < MySuperClass
end


Если я явно не включу MyModule в ClassA и ClassB, тогда моя переменная экземпляра не будет установлена ​​в этих двух классах.


Есть ли способ убедиться, что модуль self.included(базовый) метод выполняется в каждом подклассе без необходимости явно включать модуль? Поскольку он уже включен в суперкласс.

спросил(а) 2021-01-25T15:20:12+03:00 4 месяца, 4 недели назад
1
Решение
165

Переменная экземпляра класса является частной для класса. Унаследованные классы не могут получить к ним доступ напрямую. Здесь есть несколько способов.


1. Определить элемент доступа


module MyModule
def self.included(base)
base.instance_variable_set :@my_instance_variable, {}
base.extend ClassMethods
end

module ClassMethods
def my_instance_variable
# self is ClassA here, so we need to call superclass
superclass.instance_variable_get :@my_instance_variable # => {}
end
end
end

class MySuperClass
include MyModule
end

class ClassA < MySuperClass; end

ClassA.my_instance_variable # => {}


2. Больше метапрограмматического

Но есть крючок, который вызывается каждый раз, когда класс унаследован от вас. Вы можете установить переменные в этой точке. Проверьте это.


module MyModule
def self.included(base)
base.extend ClassMethods
end

module ClassMethods
# make it a class method. It will be called on target classes later.
def enhance klass
klass.instance_variable_set("@my_instance_variable", {})
end
end
end

class MySuperClass
include MyModule

# this hook will get called on 'class ClassA < MySuperClass`
def self.inherited klass
# set class instance var on child class
enhance klass
end
end

class ClassA < MySuperClass; end

ClassA.instance_variable_get '@my_instance_variable' # => {}


ПРИМЕЧАНИЕ: в этом примере каждый унаследованный класс получает свой собственный экземпляр класса var (а базовый класс не получает его). Это может быть более подходящим для вашего случая, возможно, нет.

ответил(а) 2021-01-25T15:20:12+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема