Как автоматически включить модуль в класс на основе его имени (например, помощники включены в представления) - PullRequest
0 голосов
/ 04 ноября 2011

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

Итак, у меня есть что-то вроде следующего:

app/
  models/
    people.rb
  mappers/
    people_mapper.rb

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

1 Ответ

0 голосов
/ 04 ноября 2011

вы можете попробовать что-то вроде этого:

module Mapper::Core

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

  module ClassMethods

    # model class method to include matching module
    # this will throw an error if matching class constant name does not exist
    def has_mapping
      @mapper_class = Kernel.const_get( "Mapper::#{self}Mapper" )
      include @mapper_class
    end

    # an accessor to the matching class mapper may come in handy
    def mapper_class
      @mapper_class
    end

  end
end     

, затем require и include модуля в ActiveRecord::Base в инициализаторе (убедитесь, что для вашего модуля Mapper требуются все файлы в папке 'mappers', или используйте config.autoload_paths).

Если вы вообще не хотите использовать метод класса has_mapping, вы можете попытаться переопределить self.inherited обратный вызов ActiveRecord::Base, но это может стать опасным:

  def self.included( base )
    base.extend( ClassMethods )
    base.instance_eval <<-EOF
      alias :old_inherited :inherited
      def self.inherited( subclass )
        subclass.has_mapping
        old_inherited( subclass )
      end
    EOF
  end

Я не пробовал ничего из этого, поэтому действуйте осторожно .

РЕДАКТИРОВАТЬ:

Я устал, когда писал это. Существует гораздо более простой способ автоматического включения соответствующего модуля:

module Mapper::Core
  def self.included( base )
    begin
      mapper_class = Kernel.const_get( "Mapper::#{base.name}Mapper" )
      base.instance_eval( "include #{mapper_class}" ) 
    rescue 
      Logger.info "No matching Mapper Class found for #{base.name}"
    end
  end
end

инициализировать это с:

ActiveRecord::base.instance_eval( 'include Mapper::Core' )

весь наследующий класс теперь будет include Mapper::Core, что приведет к включению соответствующего класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...