代码之家  ›  专栏  ›  技术社区  ›  Aaron Qian

插件内的别名ActiveRecord方法

  •  2
  • Aaron Qian  · 技术社区  · 15 年前

    我正在尝试编写一个插件,它以如下方式在ActiveRecord中为某些方法起别名:

    class Foo < ActiveRecord::Base
      include MyOwnPlugin
      acts_as_my_own_plugin :methods => [:bar]
    
      def bar
        puts 'do something'
      end
    end
    

    插件内部:

    module MyOwnPlugin
      def self.included(base)    
        base.class_eval do
          extend ClassMethods
        end
      end
      module ClassMethods
        def acts_as_my_own_plugin(options)
          options[:methods].each do |m|
            self.class_eval <<-END
              alias_method :origin_#{m}, :#{m}
            END
          end
        end
      end
    end
    

    这种方法不起作用,因为当运行我自己的插件时,foo-bar还没有定义,因为它还没有运行。

    将acts作为自己的插件放置:methods=>[:bar] BAR函数声明将起作用。然而,这并不漂亮。

    我希望能够像大多数插件一样将acts作为自己的插件放在类定义的顶部。

    是否有其他方法来满足这个条件?

    1 回复  |  直到 15 年前
        1
  •  5
  •   Christoph Schiessl Joeyjoejoejr    15 年前

    永远记住:Ruby中几乎所有内容都有一个回调。

    尝试以下操作:

    module MyOwnPlugin
      def self.included(base)
        base.extend(ClassMethods)
      end
    
      module ClassMethods
        # gets called from within the models
        def acts_as_my_own_plugin(options)
          # store the list of methods in a class variable and symbolize them
          @@methods = []
          options[:methods].each { |method| @@methods << method.to_sym }
        end
    
        # callback method. gets called by ruby if a new method is added.
        def method_added(name_of_method)
          if @@methods.include?(name_of_method)
            # delete the current method from our @@methods array
            # in order to avoid infinite loops
            @@methods.delete(name_of_method)
            #puts "DEBUG: #{name_of_method.to_s} has been added!"
    
            # code from your original plugin
            self.class_eval <<-END
              alias_method :origin_#{name_of_method}, :#{name_of_method}
              def #{name_of_method}
                puts "Called #{name_of_method}"
                origin_#{name_of_method}
              end
            END
    
          end
        end
      end
    end
    
    # include the plugin module in ActiveRecord::Base
    # in order to make acts_as_my_own_plugin available in all models 
    ActiveRecord::Base.class_eval do
      include MyOwnPlugin
    end
    
    # just call acts_as_my_own_plugin and define your methods afterwards
    class Foo < ActiveRecord::Base
      acts_as_my_own_plugin :methods => [:bar]
    
      def bar
        puts 'do something'
      end
    end
    

    我希望这是有用的。你能用Ruby做的疯狂的事情很酷;)

    如果要允许在调用之前和之后定义方法, acts_as_my_own_plugin 您需要再次更改代码以允许这样做。然而,困难的部分已经完成了。

    免责声明:这已经用Ruby1.8.7测试过了。可能不适用于Ruby 1.9.*。