Como métodos de classe apelido ActiveRecord dinamicamente em um rails plugin?
-
05-09-2019 - |
Pergunta
Estou tendo problemas para remover alguma duplicação eu introduzido em um rails plugin.
O código abaixo modifica a encontrar e calcular métodos de ActiveRecord da mesma maneira, mas eu fui incapaz de remover a duplicação.
Localizar e calcular métodos abaixo fazer uso da palavra-chave super-que é um obstáculo como a palavra-chave super só pode ser usado para chamar um método compartilhando o mesmo nome que o método chamando, então eu não posso mover a palavra-chave super para um método compartilhado por localizar e calcular.
Assim, na próxima eu tentei aliasing os métodos de localização e de classe calcular a partir da superclasse ActiveRecord, no entanto, eu não fui capaz de obter o direito de sintaxe para o aliasing. Se alguém pudesse me mostrar que, seria uma grande ajuda.
Se você tem uma maneira melhor de fazer isso completamente Eu adoraria para você postar isso também.
Abaixo eu aparado o código um pouco para baixo para destacar o problema:
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
Solução
Seu melhor maneira de refatorar esse código é deixar find
e calculate
inalterada, e adicione aplicar o embrulho usando uma função de nível de classe.
Aqui está rascunho, sem o seu módulo e lógica mixin:
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
Note que esta terá de ser modificado se B
tem find
já substituído ou calculate
.
Para usar esse código, primeiro fazer o seu trabalho versão corretamente, em seguida, modificá-lo para usar define_method
. (E se você precisar de desempenho extremamente alto, você pode precisar usar uma das funções *_eval
para criar os wrappers em vez de define_method
.)
Outras dicas
Esta é a opção Eu fui para, no final, graças a EMK de orientação para chegar a este ponto!
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
Para somente o alias o método find:
module SingletonMethods
def find(*args)
some_method_1
super *args.push(options)
some_method_2
end
alias :calculate :find
end