使用多个模块扩展的对象中方法的 Ruby 优先级

Posted

技术标签:

【中文标题】使用多个模块扩展的对象中方法的 Ruby 优先级【英文标题】:Ruby precedence of methods in objects extended with multiple modules 【发布时间】:2012-01-09 20:39:23 【问题描述】:

鉴于以下情况:

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 的扩展顺序如何?

【问题讨论】:

您可能可以使用extendedmethod_added 做一些事情,但是您需要在模块中或某处拥有某种优先级规则机制......呃......否则。 我在 ruby​​ doc 中找不到这两种方法。 移至伪答案以进行格式化。 【参考方案1】:

method_addedModule 中。

我实际上是指included,而不是extended,但两者也在Module中。

该机制将围绕执行以下操作:

module Foo
  def self.included(base)
    base.extend(FooMethods)
  end

  module FooMethods
    def bar
      # Whatever
    end
  end
end

Foo.included 中,您可以根据任意标准确定是否应将相关方法添加到base(包括模块的实体)。

在您的情况下,您可以检查是否已包含“更高优先级”模块,或查看该模块是否“更高优先级”模块。基于此,您将决定是否添加方法。

【讨论】:

我在尝试 Foo.method_added 时收到“NoMethodError: private method `method_added' called for Foo:Module”。 @ReedG.Law 这不是你使用它的方式,我也不相信它是你想要使用的——我认为这是一个“后”挂钩,没有帮助。 included 会更合适。【参考方案2】:

你不能;在 Ruby 中,模块包含的顺序是搜索模块的顺序 (after the current class, before parent classes)。更改“优先级”的唯一方法是以您想要的顺序包含模块,或者将它们移动到父类。

虽然不是纯 Ruby,但您可以使用 banisterfiend 的 Remix 库来更改模块顺序(或取消混合模块,或...其他事情)。

【讨论】:

我必须玩,但似乎可以使用included/extended 的一些挂钩来做到这一点,不是吗? Remix 看起来不错,但如果没有进一步评估,很难跳到那种解决方案。尽管这种功能对于使用 DCI 设计模式可能是必不可少的。【参考方案3】:

由于管理员也是注册用户,我会这样做

module Admin
  include RegisteredUser
  ...
end

然后只有

current_user.extend Admin

我不确定这是否是正确的方法。如果 Admin 和 RegisteredUser 是类,那么让 Admin 从 RegisteredUser 继承是有意义的。如果是模块,不知道。

【讨论】:

这种方法似乎有效。我能看到的唯一缺点是是否有许多模块和复杂的组合(即一个用户是管理员但不是编辑器,但管理员包括编辑器)。

以上是关于使用多个模块扩展的对象中方法的 Ruby 优先级的主要内容,如果未能解决你的问题,请参考以下文章

ruby 扩展了类和实例方法的Ruby模块

Ruby mixins:扩展和包含

在 Ruby 上设计 DAO

CSSCSS样式的优先级

CSSCSS样式的优先级

多线程(ThreadRunnableCallable)