Рубиновый приоритет методов в объектах, расширенных несколькими модулями

Учитывая следующее:

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 для изменения порядка модулей (или размешивания в модуле, или... других вещей).

Другие вопросы по тегам