English 中文(简体)
如何在Rails插件中动态别名化ActiveRecord类方法?
原标题:
  • 时间:2009-02-18 13:36:38
  •  标签:

我在移除一个在Rails插件中出现的重复时遇到了问题。

以下代码以同样的方式修改了ActiveRecord的查找和计算方法,但我无法消除重复。

下面的查找和计算方法利用了超级关键字,这是一个难点,因为超级关键字只能用于调用与调用方法名称相同的方法,所以我无法将超级关键字移动到由查找和计算共享的方法中。

所以下一步,我尝试从超类ActiveRecord别名化find和calculate类方法,但是,我一直无法正确使用别名语法。如果有人能向我展示,那将是一个很大的帮助。

如果您有更好的方法来完成这项任务,我也希望您发布出来。

我将代码缩减了一下以突出显示问题:

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
最佳回答

您重新设计代码的最佳方法是保留 find calculate 不变,并使用类级别函数进行包装。

这是一个简略草图,没有您的模块和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

请注意,如果B已经覆盖了findcalculate,则需要修改此处。

要使用此代码,请首先确保您的版本可以正常工作,然后修改它以使用 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

仅仅为找到方法创建别名:

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




相关问题
热门标签