如何在rails插件中动态地为ActiveRecord类方法添加别名?

时间:2009-02-18 13:36:38

标签: ruby-on-rails ruby ruby-on-rails-plugins

我在删除我在rails插件中引入的一些重复时遇到了问题。

下面的代码以相同的方式修改ActiveRecord的查找和计算方法,但我一直无法删除重复。

下面的查找和计算方法使用super关键字,这是一个障碍,因为super关键字只能用于调用与调用方法共享同名的方法,所以我不能将super关键字移动到查找和计算共享的方法。

接下来我尝试使用超类ActiveRecord对find和计算类方法进行别名,但是,我无法为别名获得正确的语法。如果有人能告诉我,那将是一个很大的帮助。

如果你有更好的方式完成这项工作,我也很乐意发帖。

下面我将代码略微调整一下以突出显示问题:

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 个答案:

答案 0 :(得分:1)

重构此代码的最佳方法是保持findcalculate不变,然后使用类级函数添加应用包装。

这是粗略的草图,没有你的模块和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。)

答案 1 :(得分:1)

这是我最后选择的选项,感谢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

答案 2 :(得分:0)

只是为find方法添加别名:

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