2011-11-30 80 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設計模式可能至關重要。 –