2

次の方法で 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

#acts_as_my_own_plugin が実行されるとき、Foo#bar は実行されていないためまだ定義されていないため、このアプローチは機能しません。

act_as_my_own_plugin :methods => [:bar] を置くと bar 関数宣言が機能します。しかし、これはきれいではありません。

ほとんどのプラグインがそうであるように、acts_as_my_own_plugin をクラス定義の上に配置できるようにしたいと考えています。

この条件を満たすための代替アプローチはありますか?

4

1 に答える 1

5

常に覚えておいてください: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でテストされています。Ruby1.9。*では動作しない可能性があります。

于 2009-09-03T12:16:12.757 に答える