他人のスクリプトを手直ししていて少しはまったのでメモ。
要点は、親の親クラスのinitializeを呼びたい場合に、aliasで待避しておいて呼べるようにしただけだが。
Hogeクラスを継承してHoge2とHoge3のクラスを作る。
Hoge2とHoge3クラスは初期化処理に違いがあるだけで、それ以外のコードは全く同じ。
最も直感的には、Hoge3 < Hoge2 < Hoge のような継承関係にするだろう。
ところが今回の場合、Hoge3の初期化でHogeのinitializeを呼ぶ必要があるので、(直感的には)その手を使えない。
かといって、Hoge2とHoge3に同じコードを毎回書くのも、「一方で修正したのにもう一方にその修正を入れるのを忘れた」問題が多発しそうなので、やめたい。
どうしたものか。
全部自分で書いたものなら、クラスHoge2での拡張をモジュールで定義しておいて、そのモジュールをHoge2とHoge3でそれぞれincludeするのが、おそらく最も妥当だろう。
このような感じ。
<tt>
module Hoge_ext
(拡張機能の処理)
...
end
class Hoge2 < Hoge
...
include Hoge_ext
...
end
class Hoge3 < Hoge
...
include Hoge_ext
...
end
</tt>
ところが、Hoge~Hoge2のクラスは他人の作ったもの。このような変更をすると、HogeとかHoge2がアップデートされたときに困る。
さて、どうしたものか。
以下のような感じで一件落着の模様。
class Hoge2 < Hoge
# 一瞬だけinitializeの定義を「削除」する。
# これでinitializeの定義は親クラスHogeのinitializeになる
remove_method initialize
# クラスHogeのinitializeをinitialize_hogeとして待避
alias initialize_hoge initialize
def initialize
# Hoge2の初期化処理を復活させる
...
end
end
# Hoge3クラスを忘れさせる(継承関係を変えるので)Object.sendでもできるらしい
# Object.send(:remove_const, :Hoge3)
Object.class_eval { remove_const :Hoge3 }
# Hoge2の子としてHoge3を再定義
class Hoge3 < Hoge2
def initialize
...
initialize_hoge
end
end
</tt>
要点は、親の親クラスのinitializeを呼びたい場合に、aliasで待避しておいて呼べるようにしただけだが。
Hogeクラスを継承してHoge2とHoge3のクラスを作る。
Hoge2とHoge3クラスは初期化処理に違いがあるだけで、それ以外のコードは全く同じ。
最も直感的には、Hoge3 < Hoge2 < Hoge のような継承関係にするだろう。
ところが今回の場合、Hoge3の初期化でHogeのinitializeを呼ぶ必要があるので、(直感的には)その手を使えない。
かといって、Hoge2とHoge3に同じコードを毎回書くのも、「一方で修正したのにもう一方にその修正を入れるのを忘れた」問題が多発しそうなので、やめたい。
どうしたものか。
全部自分で書いたものなら、クラスHoge2での拡張をモジュールで定義しておいて、そのモジュールをHoge2とHoge3でそれぞれincludeするのが、おそらく最も妥当だろう。
このような感じ。
<tt>
module Hoge_ext
(拡張機能の処理)
...
end
class Hoge2 < Hoge
...
include Hoge_ext
...
end
class Hoge3 < Hoge
...
include Hoge_ext
...
end
</tt>
ところが、Hoge~Hoge2のクラスは他人の作ったもの。このような変更をすると、HogeとかHoge2がアップデートされたときに困る。
さて、どうしたものか。
以下のような感じで一件落着の模様。
class Hoge2 < Hoge
# 一瞬だけinitializeの定義を「削除」する。
# これでinitializeの定義は親クラスHogeのinitializeになる
remove_method initialize
# クラスHogeのinitializeをinitialize_hogeとして待避
alias initialize_hoge initialize
def initialize
# Hoge2の初期化処理を復活させる
...
end
end
# Hoge3クラスを忘れさせる(継承関係を変えるので)Object.sendでもできるらしい
# Object.send(:remove_const, :Hoge3)
Object.class_eval { remove_const :Hoge3 }
# Hoge2の子としてHoge3を再定義
class Hoge3 < Hoge2
def initialize
...
initialize_hoge
end
end
</tt>