2011-06-02 46 views
1

我希望能夠使傳遞給我的類方法的選項(可審計)可用於實例方法。我使用模塊混合了類和實例方法。如何使用通過模塊混入的類和實例方法中的類變量

最明顯的選擇是使用一個類變量,但在嘗試訪問時,我得到一個錯誤是:

在可審計

未初始化的類變量@@ auditable_only_once

class Document 
    include Auditable 
    auditable :only_once => true 
end 

# The mixin 
module Auditable 
    def self.included(base) 
    base.extend(ClassMethods) 
    end 

    module ClassMethods 
    def auditable(options = {}) 

     options[:only_once] ||= false 

     class_eval do 
     # SET THE OPTION HERE!! 
     @@auditable_only_once = options[:only_once] 
     end 
     end 
    end 

    private 

    def audit(action) 
     # AND READ IT BACK LATER HERE 
     return if @@auditable_only_once && self.audit_item 
     AuditItem.create(:auditable => self, :tag => "#{self.class.to_s}_#{action}".downcase, :user => self.student) 
    end  
    end 

我已經剝去了一些代碼,使這個更容易閱讀,完整的代碼在這裏:https://gist.github.com/1004399(編輯:Gist現在包括解決方案)

+0

在版本在GitHub上只有指定當一個@在auditable_only_once前(線16),但你已經在代碼中解決了這個問題。您是否使用該修復測試了代碼?它仍然不起作用嗎? – Jonathan 2011-06-02 13:42:30

+0

感謝您發現,我實際上嘗試過單個和雙個@,所以必須將更新版本的代碼複製到Gist。現在修復。 – Kris 2011-06-03 15:15:03

回答

0

使用@@類實例變量不規則,嚴格要求時的次數極少。大多數情況下,他們似乎會造成麻煩或混亂。通常,您可以在類上下文中使用常規實例變量而不會出現問題。

你可能想要做的是爲這種事情使用不同的模板。如果您擁有由ActiveSupport提供的mattr_accessor,則可能需要使用該變量而不是該變量,或者始終可以在自己的ClassMethods組件中編寫自己的等效項。

我使用的一種方法是將你的擴展分解爲兩個模塊,一個鉤子和一個實現。掛鉤只會增加的方法可以使用,如果需要添加的方法,其餘的基類,但在其他方面不污染命名空間:

module ClassExtender 
    def self.included(base) 
    base.send(:extend, self) 
    end 

    def engage(options = { }) 
    extend ClassExtenderMethods::ClassMethods 
    include ClassExtenderMethods::InstanceMethods 

    self.class_extender_options.merge!(options) 
    end 
end 

engage方法可以被調用任何你喜歡的,在你的例子中,它是auditable

接下來創建用於該分機添加類和實例方法的容器的模塊,它是行使:

module ClassExtenderMethods 
    module ClassMethods 
    def class_extender_options 
     @class_extender_options ||= { 
     :default_false => false 
     } 
    end 
    end 

    module InstanceMethods 
    def instance_method_example 
     :example 
    end 
    end 
end 

在這種情況下,有一個簡單的方法class_extender_options可用於查詢或修改特定課程的選項。這避免了必須直接使用實例變量。還添加了一個示例實例方法。

您可以定義一個簡單的例子:

class Foo 
    include ClassExtender 

    engage(:true => true) 
end 

然後測試其是否工作正常:

Foo.class_extender_options 
# => {:default_false=>false, :true=>true} 

foo = Foo.new 
foo.instance_method_example 
# => :example 
+1

請注意,我使用cattr_accessor(而不是mattr_accessor)來創建類屬性(我在Rails中這樣工作)並從我使用self.class.only_once的實例方法中訪問它 – Kris 2011-06-14 17:44:59

相關問題