2011-11-30 78 views
1

如下:红宝石优先扩展了由于多个模块

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的延伸顺序吗?

+0

你可能可以用'extended'或'method_added'做一些事情,但是你需要在模块或某个地方有某种优先级规则机制... erm ... else。 –

+0

我无法在ruby doc中找到这两种方法之一。 –

+0

已移至伪格式化答案。 –

回答

2

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(包括模块实体)。

对于您的情况,您可以检查是否已包含“更高优先级”模块,或查看模块是否为“更高优先级”模块。根据你决定是否添加方法。

+0

当我尝试使用Foo.method_added时,我得到了“NoMethodError:私有方法'method_added'调用Foo:Module”。 –

+0

@ ReedG.Law这不是你如何使用它,我也不相信它是你想要使用的 - 我认为这是一个“之后”的钩子,这没有帮助。 'included'会更合适。 –

1

由于管理员的也是RegisteredUser,我会做

module Admin 
    include RegisteredUser 
    ... 
end 

,然后只

current_user.extend Admin 

我不知道这是否是正确的方法。如果Admin和RegisteredUser是类,它将有助于Admin从RegisteredUser继承。在模块的情况下,不知道。

+0

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

1

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

虽然不是纯粹的Ruby,但可以使用由banisterfiend创建的Remix库来更改模块排序(或者取消整合模块或其他内容)。

+0

我不得不玩,但它确定好像挂钩到'included' /'extended'可以用来做到这一点,不是吗? –

+0

混音看起来不错,但如果没有进一步的评估就很难跳到这种解决方案。尽管这种功能对于使用DCI设计模式可能至关重要。 –