Как динамически псевдонимировать методы класса ActiveRecord в плагине rails?

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

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

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

Итак, затем я попытался использовать псевдонимы для методов класса find и calculate из суперкласса 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

person Eliot Sykes    schedule 18.02.2009    source источник


Ответы (3)


Лучший способ реорганизовать этот код — оставить 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.)

person emk    schedule 18.02.2009
comment
Спасибо, emk, ваше решение привело меня к моему окончательному решению, которое я представил ниже. - person Eliot Sykes; 26.02.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
person Eliot Sykes    schedule 26.02.2009

Просто псевдоним метода find:

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