Как псевдоним методов класса ActiveRecord динамически в плагине rails?
У меня проблемы с удалением дублирования, которое я представил в плагине rails.
Приведенный ниже код изменяет методы поиска и вычисления ActiveRecord таким же образом, но я не смог удалить дублирование.
Приведенные ниже методы поиска и вычисления используют ключевое слово super, которое является одним препятствием, поскольку ключевое слово super можно использовать только для вызова метода, имеющего то же имя, что и вызывающий метод, поэтому я не могу переместить ключевое слово super в метод shared найти и рассчитать.
Итак, затем я попытался создать псевдонимы методов поиска и вычисления класса из суперкласса 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 ответа
Лучший способ изменить этот код - это оставить 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
.)
Это вариант, который я выбрал в конце, спасибо 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
Для псевдонима метод find:
module SingletonMethods
def find(*args)
some_method_1
super *args.push(options)
some_method_2
end
alias :calculate :find
end