2010-02-05 52 views
3

目前我將每個選項存儲在它自己的類屬性中,但是當我需要從實例方法訪問傳遞的選項時,這導致難以閱讀代碼。如何從實例方法訪問傳遞給acts_as插件(ActiveRecord裝飾器)的選項?

例如,如果我傳遞列名作爲選項,我必須使用self.send(self.class.path_finder_column)從實例方法獲取列值。

注意我已經在class屬性前加上了我的插件名稱,以防止名稱衝突。

下面是一個插件的簡單代碼示例,該插件傳遞一個選項column,然後通過實例方法set_path訪問該選項。獲取者/設置者是否可以簡化爲更具可讀性?

# usage: path_find :column => 'path' 

module PathFinder  
    def path_finder(options = {}) 
    send :include, InstanceMethods 

    # Create class attributes for options 
    self.cattr_accessor :path_finder_column 
    self.path_finder_column = options[:column] 

    module InstanceMethods 
     def set_path   
     # setter 
     self.send(self.class.path_finder_column + '=', 'some value') 
     # getter 
     self.send(self.class.path_finder_column) 
     end 
    end 
    end 
end 

ActiveRecord::Base.send :extend, PathFinder 

回答

1

您可以在運行時生成所有這些方法。

module PathFinder 
    def path_finder(options = {}) 

    # Create class attributes for options 
    self.cattr_accessor :path_finder_options 
    self.path_finder_options = options 

    class_eval <<-RUBY 
     def path_finder(value) 
     self.#{options[:column]} = value 
     end 

     def path_finder 
     self.#{options[:column]} 
     end 
    RUBY 
    end 
end 

ActiveRecord::Base.send :extend, PathFinder 

除非你需要存儲的選項,你也可以刪除線

self.cattr_accessor :path_finder_options 
self.path_finder_options = options 

請注意,我的解決方案並不需要一個setter和一個getter只要你總是使用path_finderpath_finder= 。 所以,最短的解決方案(假設只是:列選項,並沒有其他要求)

module PathFinder 
    def path_finder(options = {}) 

    # here more logic 
    # ... 

    class_eval <<-RUBY 
     def path_finder(value) 
     self.#{options[:column]} = value 
     end 

     def path_finder 
     self.#{options[:column]} 
     end 
    RUBY 
    end 
end 

ActiveRecord::Base.send :extend, PathFinder 

這種方法類似於acts_as_listacts_as_tree採用的一個。

-1

您可以使用cattr_accessor將配置值存儲在類級別並用於所有實例方法。您可以在http://github.com/smsohan/acts_as_permalinkable/blob/master/lib/active_record/acts/permalinkable.rb

看代碼中看到的一個例子是這樣的:

def acts_as_permalinkable(options = {}) 
      send :cattr_accessor, :permalink_options 
      self.permalink_options = { :permalink_method => :name, :permalink_field_name => :permalink, :length => 200 } 
      self.permalink_options.update(options) if options.is_a?(Hash) 

      send :include, InstanceMethods 
      send :after_create, :generate_permalink 
     end 

希望它能幫助!

+0

-1:發佈在問題中的代碼已經使用了cattr_accessor。 – EmFi

1

以cattr_accessor開頭爲給出的每個符號創建一個類變量。在ruby中,類變量的名字前綴爲@@。

因此,您可以使用@@path_finder_column來代替self.class.path_finder_column

但是,考慮到接下來會提出什麼,這是一個有爭議的問題。

在問題中的代碼提供的具體情況。您定義的組合getter和setter不適合ruby約定。看到如何使用通用名稱重新標記爲path_finder_column生成的訪問器,可以將其全部縮減爲只有一對別名。

假設有在組合訪問(如何應該知道是否要獲取或設置的代碼)的錯誤,最終確定的模塊將是這樣的:

module PathFinder  
    def path_finder(options = {}) 
    send :include, InstanceMethods 

    # Create class attributes for options 
    self.cattr_accessor :path_finder_column 
    self.path_finder_column = options[:column] 
    alias :set_path, path_finder_column 
    alias :set_path=, "#{path_finder_column}=" 
    end 

    module InstanceMethods 
    # other instance methods here. 
    end 
end 
相關問題