Каждый из этих примеров относится к разным случаям.
Если вы пишете методы, которые применяются ко всем объектам, то вы открываете класс Object
, чтобы все объекты могли получить к нему доступ.Если вы пишете методы, применимые ко всем модулям, вы открываете Module
.Всякий раз, когда вы открываете класс для добавления методов, методы должны применяться к всем экземплярам класса и ничему другому .
Расширение модуля Kernel
отличается: люди делают это для добавления методовэто должно быть доступно для каждой области видимости, но не в качестве методов, вызываемых явным образом для объекта, делая их закрытыми.
Когда вы находитесь за пределами любого оператора class
или module
, вы находитесь вобласть действия объекта main
и определяемые вами методы по умолчанию являются закрытыми методами Object
.Это хорошо для небольших или простых программ, но вы в конечном итоге захотите использовать надлежащие модули в качестве пространств имен для организации ваших методов.
В качестве заключительного замечания по этому вопросу, вы всегда должны быть уверены, что вам действительно нужны методывы добавляете во встроенные классы и модули, чтобы они были доступны для всего в вашем приложении, включая внешние включения , потому что все они имеют общие встроенные модули.
Теперь, чтобы применить это, чтобы ответить на ваш вопрос,Поскольку вы определяете метод, который создает методы доступа для переменных класса, вы должны поместить его в класс Class
, поскольку он применяется ко всем классам и ничего больше.Наконец, вы, скорее всего, будете использовать его только в определениях классов (в операторе class
), поэтому мы должны сделать его закрытым:
class Class
private
def c_attr_accessor(name)
# ...
end
end
class User
c_attr_accessor :class_variable_name
# ...
end
Если он вам действительно не нужен в каждом классе (может быть, простонесколько), затем создайте «модуль mixin», чтобы расширить каждый класс, который нуждается в этой функции:
module ClassVariableAccessor
private
def c_attr_accessor(name)
# ...
end
end
class User
extend ClassVariableAccessor
c_attr_accessor :class_variable_name
# ...
end
Обратите внимание, что вы используете Object#extend
для добавления c_attr_accessor
только к объекту User
(помните, что классы являются объектами, вы много услышите об этом, если вы новичок в метапрограммировании Ruby).
Существует еще один способ реализации последнего примера, который работает путем явного расширения его базового класса через Module#included(base_class)
«Метод ловушки» вызывается всякий раз, когда модуль включен, а базовый класс передается в base_class
:
module ClassVariableAccessor
def included(base_class)
base_class.extend ClassMethods
end
module ClassMethods
def c_attr_accessor(name)
# ...
end
end
end
class User
include ClassVariableAccessor
c_attr_accessor :class_variable_name
# ...
end
. Я рекомендую это последнее решение, потому что оно является наиболее общим и использует простой интерфейс, который не требуетсябыть обновленным.Надеюсь, это не так уж и много!