2016-05-17 18 views
1

因此,儘管我完全反對擴大現有類這樣,有時(黑客rspec)有必要做這樣的事情類變量:可以訪問一個模塊中定義

module MyModule 
    module ClassMethods 
    def define_something(name) 
     @@names ||= [] 
     @@names << name 
    end 
    end 
    def self.included(base) 
    base.extend ClassMethods 
    end 
    def all_names 
    @@names 
    end 
end 
class Example 
    include MyModule 
    define_something "one" 
    define_something "two" 
end 
Example.new.all_names 

,然後它產生這個錯誤:

NameError: uninitialized class variable @@names in MyModule 

而且據我所知,因爲在寫MyModule::ClassMethods的時間 - 我們在示例中未類(不self.)工作,所以我嘗試:

module MyModule 
    module ClassMethods 
    def define_something(name) 
     @names ||= [] 
     @names << name 
    end 
    end 
    def self.included(base) 
    base.extend ClassMethods 
    end 
    def all_names 
    @@names 
    end 
end 
class Example 
    include MyModule 
    define_something "one" 
    define_something "two" 
end 
Example.new.all_names 

它不工作,要麼,我終於結束了:

module MyModule 
    module ClassMethods 
    def define_something(name) 
     @names << name 
    end 
    end 
    def self.included(base) 
    base.instance_variable_set(:@names, []) 
    base.send(:define_method, :all_names) { base.instance_variable_get(:@names) } 
    base.extend ClassMethods 
    end 
end 
class Example 
    include MyModule 
    define_something "one" 
    define_something "two" 
end 
Example.new.all_names 

有沒有更好的方式來做到這一點?

+0

'@@'和'@'是完全不同的。無論您處於類還是實例上下文中,都不能使用@ @訪問「@@」變量,反之亦然。 – meagar

回答

4

從設計的角度來看,避免使用實例變量引用穿過類/實例行通常會更好。這通常更加清晰:

module MyModule 
    module ClassMethods 
    def define_something(name) 
     self.defined_somethings << name 
    end 

    def defined_somethings 
     @_my_module_names ||= [] 
    end 
    end 

    def self.included(base) 
    base.extend ClassMethods 
    end 

    def all_names 
    self.class.defined_somethings 
    end 
end 

class Example 
    include MyModule 
    define_something "one" 
    define_something "two" 
end 

Example.new.all_names.inspect 
#=> ["one","two"] 

我在這裏已經注意到創建一個帶有詳細名稱的類級實例變量。調用它@name可能會使其與由包含此模塊的類定義的變量發生衝突。請記住,在設計mixin代碼時,你是客人,你需要格外禮貌。

@@name這樣的類型實例變量有時會遇到麻煩,因爲它們最終可能會跨越繼承鏈,這取決於它們的使用方式。定義一個方法意味着你可以在鏈中的任何位置覆蓋它,這對於一個共享變量來說是不可能的。

換句話說,將實例的類作爲一個單獨的對象來處理,並明確定義明確的方法調用以維持該分離。

1

嘗試使用以下

module MyModule 
    module ClassMethods 
    def define_something(name) 
     @names ||= [] 
     @names << name 
    end 
    end 
    def self.included(base) 
    base.extend ClassMethods 
    end 
    def all_names 
    self.class.instance_variable_get(:@names) 
    end 
end 
class Example 
    include MyModule 
    define_something "one" 
    define_something "two" 
end 

Example.new.all_names 

類變量可使用操作者@@從類水平的方法即self.方法進行訪問。

@ tadman的回答有類似問題的一般方法(以提供的模塊來實現的功能通常寶石發現)

相關問題