class_evalを使用していくつかのクラスの機能を拡張したいと思います。私はクラスに他のクラスからいくつかのメソッドを継承させたいと思います。Rubyのメタプログラミング:class_evalで継承を定義する
すなわち:
SomeClass.class_eval do
# force inheritence from some other class
end
それを達成するための最良の方法は何ですか?
class_evalを使用していくつかのクラスの機能を拡張したいと思います。私はクラスに他のクラスからいくつかのメソッドを継承させたいと思います。Rubyのメタプログラミング:class_evalで継承を定義する
すなわち:
SomeClass.class_eval do
# force inheritence from some other class
end
それを達成するための最良の方法は何ですか?
既存の機能を上書きすることが難しい場合は、これらの既存のメソッドをモジュールに定義する必要があります。
class SomeClass
include DefaultBehaviour
end
module DefaultBehaviour
def run
puts "ran default"
end
end
module AlternateBehaviour
def run
puts "ran alternate"
end
end
SomeClass.class_eval {
include AlternateBehaviour
}
SomeClass.new.run #=> "ran alternate"
ルビーのメソッドルックアップパスが原因です。
SomeClass - > Objectとして開始します。
AlternateBehaviourを含めると、SomeClass - > AlternateBehaviour - > Objectになります。したがって、SomeClassで直接定義されたメソッドが優先されます。
ただし、これらのメソッドがDefaultBehaviourで定義されている場合、ルックアップパスはSomeClass - > AlternateBehaviour - > DefaultBehaviour - > Objectになり、代替メソッドが優先されます。どのモジュールが最後に含まれていたかが最優先です。あなたは、元のクラスのコントロールを持っていない場合は、あなたが代わりに行うことができます場合は
:
module AlternateBehaviour
def self.included(base)
base.send(:remove_method, :run)
end
def run
puts "ran alternate"
end
end
この時点で、一つはあなただけ
を実行して、オフに良いかもしれないかどうかを疑問に開始しますがSomeClass.class_eval {
def run
"ran alternate"
end
end
include
とextend
をお試しください。いずれもhereと記載されています。モジュールでのみ動作します。ただすることはできませんは、すでに作成された後にRubyでクラスのスーパークラスを変更/追加することはできません。
ただ1つの問題:この記事の3番目のコメントで説明されているクラスの既存のメソッドをオーバーライドすることはできません。
さらに詳しい情報については、thisトピックを参照してください。
すでにクラスがあり、そのメソッドを外部モジュールで定義されているものからオーバーライドしたい場合はどうしたらいいですか? – alexs333
投稿を更新しています... – Jwosty
ルビはメソッドを見つけるために継承階層を後戻りさせ、クラスのすぐ上の階層にそのモジュールを挿入するだけなので、モジュールは実際にクラス自体で指定された機能をオーバーライドすることはありません。クラス自体は依然としてチェックされた最初の場所です。 ...これは、この問題の正しい解決策であると私はまだJwostyに同意します。クラスで既に定義されているメソッドを実際にオーバーライドする必要がある場合は、独自のモジュールで定義して解決できます。 – Burke
複雑なのは、私がモジュールにリファクタリングすることができないサードパーティのエンジンコードの中に座っているクラスメソッドをオーバーライドしようとしているときです:(そうでなければあなたのソリューションは動作します... – alexs333
それでは、ソリューションを更新してください。 – Burke
なぜあなたはclass_evalを使う必要がありますか?メソッド定義を直接class_evalにダンプすることもできますし、置換メソッドを他の場所に配置したい場合は、置換を定義する前に既存のメソッドを削除するモジュールを作成することもできます。 – Burke