1

ActiveRecord モデルの機能を拡張するモジュールを作成しています。

これが私の初期設定です。

私のクラス:

class MyClass < ActiveRecord::Base
  is_my_modiable
end

そしてモジュール:

module MyMod
  def self.is_my_modiable
    class_eval do 
      def new_method
        self.mod = true
        self.save!
      end
   end
  end
end
ActiveRecord::Base(extend,MyMod)

私が今やりたいことはnew_method、ブロックを渡すことによって の機能を拡張することです。このようなもの:

class MyClass < ActiveRecord::Base
  is_my_modiable do
    self.something_special
  end
end

module MyMod
  def self.is_my_modiable
    class_eval do 
      def new_method
        yield if block_given?
        self.mod = true
        self.save!
      end
   end
  end
end

これは機能しませんが、理にかなっています。class_eval では、new_method は実行されておらず、定義されているだけなので、yield ステートメントは、メソッドが実際に呼び出されるまで実行されません。

ブロックを class_eval 内のクラス変数に割り当て、メソッド内でそのクラス変数を呼び出そうとしましたが、ブロックをメソッドに渡さなくても、すべての is_my_modiable モデルでブロックが呼び出されていました。

同じ効果を得るためにメソッドをオーバーライドするだけかもしれませんが、もっとエレガントな方法があることを願っています。

4

2 に答える 2

2

私があなたを正しく理解していれば、渡されたブロックをクラスオブジェクトのインスタンス変数に保存し、それをインスタンスメソッドで評価することでこれを解決できます。

bl.call元のコンテキスト (クラスのコンテキスト) で実行され、この現在のインスタンスのスコープで実行する必要があるため、ここでは行いません。

module MyMod
  def is_my_modiable(&block)
    class_eval do
      @stored_block = block # back up block
      def new_method
        bl = self.class.instance_variable_get(:@stored_block) # get from class and execute
        instance_eval(&bl) if bl
        self.mod = true
        self.save!
      end
    end
  end
end

class MyClass
  extend MyMod

  is_my_modiable do
    puts "in my modiable block"
    self.something_special
  end

  def something_special
    puts "in something special"
  end

  attr_accessor :mod
  def save!; end
end

MyClass.new.new_method
# >> in my modiable block
# >> in something special
于 2013-11-01T09:00:54.163 に答える
1

これを行うには、ブロックをメソッド パラメーターとして割り当てます。

module MyMod
  def self.is_my_modiable
    class_eval do 
      def new_method(&block)
        block.call if block
        self.mod = true
        self.save!
      end
   end
  end
end
于 2013-11-01T08:58:29.373 に答える