3

私はヘルペスダーピーの瞬間を過ごしています。私はこれがうまくいったと断言できた:

module StubbedGreeting
  def sayit
    puts "StubbedGreeting"
  end
end

module RegularGreeting
  def sayit
    puts "RegularGreeting"
  end
end

class Greeting
  def sayit
    raise "Gotta catch me!"
  end
end

class GreetingIncludes
  include RegularGreeting
end

begin
  Greeting.send(:include, StubbedGreeting)
  Greeting.new.sayit
rescue Exception
  puts "Exception raised"
end

GreetingIncludes.send(:include, StubbedGreeting)
GreetingIncludes.new.sayit

ここで何が起こるかというとGreeting.new.sayitrescueブロックが呼び出され、StubbedGreeting による上書きの試行が無視されます。

ただし、GreetingIncludes.new.sayit結果は「StubbedGreeting」であり、例外ではありません。

モジュールは別のモジュールのメソッドを上書きできますが、クラスで直接定義されているメソッドは上書きできませんか?

私はこれを回避する方法を知っていますが、奇妙だと思いました。

4

1 に答える 1

4

モジュールをインクルードする場合、そのメソッドはメソッド解決順序でクラスとその親クラスのメソッドの間に配置されます。そのため、実際にどのメソッドを呼び出すかを決定する際、ruby はまず次の順序でメソッドを検索します。一致するメソッドが見つかった場合、検索は中止され、このメソッドが使用されます。

  • オブジェクトのシングルトン クラス
  • 最後に含まれたものから最初に含まれたものまでのシングルトンクラスに含まれるモジュール
  • オブジェクトのクラス
  • クラスに含まれるモジュール

Classこれは、クラスに到達するまで、親クラスごとに続行されます。

ご覧のとおり、モジュールはメソッド解決順序で実際のクラスの後ろに来るため、クラス自体で定義されたメソッドを実際にオーバーライドすることはできません。そのようなメソッドを本当にオーバーライドする必要がある場合は、alias_methodまたはalias_method_chainを使用してメソッドを「名前変更」できます。

今後の Ruby 2.0 では、目的を達成するクラスの前にモジュールを含めるprepend メカニズムがあります。しかし、まだリリースされていません。

于 2012-08-28T07:25:55.113 に答える