このモジュールを含めることは、動的に生成された方法を無効にしないのはなぜですか?

StackOverflow https://stackoverflow.com/questions/4741373

  •  12-10-2019
  •  | 
  •  

質問

モジュールを含めることにより、動的に生成された方法をオーバーライドしようとしています。

以下の例では、波紋協会が追加します rows= テーブルへの方法。私はその方法を呼び出したいだけでなく、その後いくつかの追加のことをしたいと思います。

モジュールをオーバーライドするモジュールを作成しました。 row= 電話することができます super 既存の方法を使用します。

class Table

  # Ripple association - creates rows= method
  many :rows, :class_name => Table::Row

  # Hacky first attempt to use the dynamically-created
  # method and also do additional stuff - I would actually
  # move this code elsewhere if it worked
  module RowNormalizer
    def rows=(*args)
      rows = super
      rows.map!(&:normalize_prior_year)
    end
  end
  include RowNormalizer

end

しかし、私の新しい rows= 私がその内部に例外を提起した場合、何も起こらないという事実から証明されるように、決して呼ばれることはありません。

モジュールが含まれていることはわかっています。なぜなら、これを入れれば、例外が提起されるからです。

      included do
        raise 'I got included, woo!'
      end

また、代わりに rows=, 、モジュールが定義します somethingelse=, 、その方法は呼ばれます。

動的に生成されたモジュールメソッドを無効にしないのはなぜですか?

役に立ちましたか?

解決

実験をしましょう:

class A; def x; 'hi' end end
module B; def x; super + ' john' end end
A.class_eval { include B }

A.new.x
=> "hi" # oops

何故ですか?答えは簡単です:

A.ancestors
=> [A, B, Object, Kernel, BasicObject]

B 前です A 先祖チェーンで(あなたはこれをと考えることができます B であること 中身 A)。したがって A.x 常に優先されます B.x.

ただし、これは回避できます。

class A
  def x
    'hi'
  end
end

module B
  # Define a method with a different name
  def x_after
    x_before + ' john'
  end

  # And set up aliases on the inclusion :)
  # We can use `alias new_name old_name`
  def self.included(klass)
    klass.class_eval {
      alias :x_before :x 
      alias :x :x_after
    }
  end
end

A.class_eval { include B }

A.new.x #=> "hi john"

ActiveSupport(したがってレール)を使用すると、このパターンが実装されています alias_method_chain(target, feature) http://apidock.com/rails/module/alias_method_chain:

module B
  def self.included(base)
    base.alias_method_chain :x, :feature
  end

  def x_with_feature
    x_without_feature + " John"
  end
end

アップデート Ruby 2には付属しています モジュール#プレップエンド, 、の方法を無効にします A, 、これを作っています alias ほとんどのユースケースでは不要です。

他のヒント

動的に生成されたモジュールメソッドを無効にしないのはなぜですか?

それが継承の仕組みではないからです。クラスで定義された方法は、他のクラス/モジュールから継承されたものをオーバーライドしますが、その逆ではありません。

Ruby 2.0にはあります Module#prepend, 、同じように機能します Module#include, 、モジュールを挿入することを除きます サブクラス 継承チェーンのスーパークラスの代わりに。

もし、あんたが extend クラスのインスタンス、あなたはそれをすることができます。

class A
  def initialize
    extend(B)
  end
  def hi
    'hi'
  end
end
module B
  def hi
    super[0,1] + 'ello'
  end
end

obj = A.new
obj.hi #=> 'hello'
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top