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
Foi útil?

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top