Как получить доступ к параметрам, переданным плагину act_as (декоратору ActiveRecord) из методов экземпляра? - PullRequest
3 голосов
/ 05 февраля 2010

В настоящий момент я храню каждую опцию в своем собственном атрибуте класса, но это приводит к затруднению чтения кода, когда мне нужен доступ к переданным опциям из методов экземпляра.

Например, если я передаю имя столбца в качестве опции, я должен использовать 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

Ответы [ 3 ]

1 голос
/ 08 февраля 2010

Для начала cattr_accessor создает переменную класса для каждого заданного символа. В ruby ​​имена переменных классов имеют префикс @@.

Таким образом, вы можете использовать @@path_finder_column вместо self.class.path_finder_column.

Однако это спорный вопрос, учитывая, что я собираюсь предложить дальше.

В конкретном случае представлен код в вопросе. Определенные вами методы получения и установки не соответствуют соглашениям 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
1 голос
/ 10 февраля 2010

Вы можете генерировать все эти методы во время выполнения.

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

Обратите внимание, что моему решению не нужны установщик и получатель, если вы всегда используете path_finder и path_finder=. Итак, самое короткое решение (при условии, что указана только опция: column и никаких других требований)

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_list и acts_as_tree.

0 голосов
/ 08 февраля 2010

Вы можете использовать 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

Надеюсь, это поможет!

...