Как псевдоним методов класса ActiveRecord динамически в плагине rails? - PullRequest
1 голос
/ 18 февраля 2009

У меня проблемы с удалением дублирования, которое я представил в плагине rails.

Приведенный ниже код изменяет методы поиска и вычисления ActiveRecord таким же образом, но мне не удалось удалить дублирование.

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

Итак, затем я попытался наложить псевдонимы методов поиска и вычисления класса из суперкласса ActiveRecord, однако мне не удалось получить правильный синтаксис для псевдонимов. Если бы кто-то мог показать мне это, это было бы очень полезно.

Если у вас есть лучший способ сделать это, я бы тоже хотел, чтобы вы опубликовали это.

Ниже я немного урезал код, чтобы выделить проблему:

module Geocodable #:nodoc:

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

  module ClassMethods
    def acts_as_geocodable(options = {})
      extend Geocodable::SingletonMethods
    end
  end

  module SingletonMethods

    def find(*args)
      some_method_1
      super *args.push(options)
      some_method_2
    end

    # TODO: Remove duplication of find above and calculate below.

    def calculate(*args)
      some_method_1
      super *args.push(options)
      some_method_2
    end
  end
end

Ответы [ 3 ]

1 голос
/ 26 февраля 2009

Это вариант, который я выбрал в конце, спасибо emk за руководство, чтобы добраться до этой точки!

module Geocodable

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

  module ClassMethods
    def acts_as_geocodable(options = {})
      geoify_query_methods
    end

    private
      # This is where the duplication has been removed
      def geoify_query_methods
        class << self
          [:calculate, :find].each do |method_name|
            define_method method_name do |*args|
              some_method_1
              super *args.push(options)
              some_method_2
            end
          end
        end
      end

  end
end
1 голос
/ 18 февраля 2009

Лучший способ реорганизовать этот код - оставить find и calculate без изменений и добавить применить обтекание с использованием функции уровня класса.

Вот примерный набросок, без вашего модуля и логики смешивания:

class A
  def find x
    puts 'finding'
  end

  def calculate x
    puts 'calculating'
  end
end

class B < A
  def self.make_wrapper_method name
    define_method name do |*args|
      puts "entering"
      result = super *args
      puts "exiting"
      result
    end
  end

  make_wrapper_method :find
  make_wrapper_method :calculate
end

Обратите внимание, что это необходимо изменить, если B уже переопределено find или calculate.

Чтобы использовать этот код, сначала заставьте вашу версию работать правильно, а затем измените ее для использования define_method. (И если вам нужна чрезвычайно высокая производительность, вам может понадобиться использовать одну из *_eval функций для создания оболочек вместо define_method.)

0 голосов
/ 19 февраля 2009

Для псевдонима метод поиска:

module SingletonMethods
  def find(*args)
    some_method_1
    super *args.push(options)
    some_method_2
  end
  alias :calculate :find
end
...