Рубиновый приоритет методов в объектах, расширенных несколькими модулями
Учитывая следующее:
class User; attr_accessor :roles; end
module RegisteredUser
def default_context
Submission
end
end
module Admin
def default_context
Review
end
end
current_user = User.new
current_user.roles = ["registered_user", "admin"]
current_user.roles.each do |role|
role_module = role.gsub(/ /, '_').camelize
if module_exists?(role_module)
current_user.extend role_module.constantize
end
end
context = self.extend current_user.default_context
Есть ли способ установить приоритет User#default_context
? То есть могу ли я сказать, что Admin#default_context
всегда имеет приоритет над RegisteredUser#default_context
независимо от того, в каком порядке current_user
продлен?
3 ответа
method_added
в Module
,
Я на самом деле имел в виду included
не extended
, но оба также в Module
,
Механизм будет вращаться вокруг выполнения чего-то вроде этого:
module Foo
def self.included(base)
base.extend(FooMethods)
end
module FooMethods
def bar
# Whatever
end
end
end
внутри Foo.included
на основе произвольных критериев вы можете определить, следует ли добавлять к base
(сущность, включающая модуль).
В вашем случае вы можете проверить, был ли включен модуль с более высоким приоритетом, или посмотреть, является ли этот модуль модулем с более высоким приоритетом. Исходя из этого, вы решите, добавлять ли методы.
Так как администратор также является зарегистрированным пользователем, я бы сделал
module Admin
include RegisteredUser
...
end
и только потом
current_user.extend Admin
Я не уверен, что это правильный путь. Если бы Admin и RegisteredUser были классами, было бы целесообразно сделать так, чтобы Admin наследовал от RegisteredUser. В случае модулей, не знаю.
Ты не можешь; в Ruby порядок включения модулей - это порядок поиска модулей ( после текущего класса, перед родительскими классами). Единственный способ изменить "приоритет" - включить модули в нужном вам порядке или переместить их в родительский класс.
Хотя это и не чистый Ruby, вы можете использовать библиотеку Remix с помощью banisterfiend для изменения порядка модулей (или размешивания в модуле, или... других вещей).