2010-02-05 4 views
3

Au moment où je stocke chaque option dans son propre attribut de classe, mais cela conduit à un code difficile à lire lorsque j'ai besoin d'accéder aux options passées à partir des méthodes d'instance.Comment accéder aux options passées à un plugin acts_as (décorateur ActiveRecord) à partir de méthodes d'instance?

Par exemple, si je transmets un nom de colonne en tant qu'option, je dois utiliser self.send(self.class.path_finder_column) pour obtenir la valeur de la colonne à partir d'une méthode d'instance.

Remarque J'ai préfixé l'attribut class avec le nom de mon plugin pour éviter les conflits de noms.

Voici un exemple de code simple d'un plugin auquel est passée une option, column, à laquelle on accède à partir de la méthode d'instance set_path. Les getters/setters peuvent-ils être simplifiés pour être plus lisibles?

# 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 

Répondre

1

Vous pouvez générer toutes ces méthodes lors de l'exécution .

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 

Sauf si vous avez besoin de stocker les options, vous pouvez également supprimer les lignes

self.cattr_accessor :path_finder_options 
self.path_finder_options = options 

Notez que ma solution n'a pas besoin d'un setter et un getter aussi longtemps que vous utilisez toujours path_finder et path_finder= . Ainsi, la plus courte est la solution (en supposant que l'option: colonne et pas d'autres exigences)

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 

Cette approche est similaire à celle adoptée par acts_as_list et acts_as_tree.

-1

Vous pouvez utiliser cattr_accessor pour stocker la valeur de configuration au niveau de la classe et l'utiliser dans toutes vos méthodes d'instance. Vous pouvez voir un exemple à http://github.com/smsohan/acts_as_permalinkable/blob/master/lib/active_record/acts/permalinkable.rb

Le code à regarder est la suivante:

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 

it helps!

+0

-1: Le code affiché dans la question fait déjà usage de cattr_accessor. – EmFi

1

Pour commencer avec cattr_accessor, crée une variable de classe pour chaque symbole donné. Dans ruby, les variables de classe ont leurs noms préfixés par @@. Vous pouvez donc utiliser @@path_finder_column à la place de self.class.path_finder_column.

Cependant, c'est un point discutable compte tenu de ce que je vais suggérer ensuite.

Dans le cas spécifique présenté par le code dans la question. La combinaison getter et setter que vous avez définie ne correspond pas aux conventions ruby. En voyant comment vous modifiez fondamentalement les accesseurs générés pour le path_finder_column avec un nom générique, vous pouvez le réduire à une paire d'alias.

En supposant qu'il ya une erreur dans l'accesseur combo (comment est le code censé savoir si pour obtenir ou définir), le module finalisé ressemblera à ceci:

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 
Questions connexes