複雑な継承関係がある状態でオブジェクトのメソッドを呼び出すと、どのような順番でメソッドが呼び出されているかというお話。
原則は
- 特異クラスはクラスの前に呼び出される
- Moduleは
include
したクラスやModuleの後に呼び出される - Moduleを複数
include
すると後でinclude
したものが先に呼び出される
継承
class Parent
def hello
p "hello Parent"
super
end
end
class Child < Parent
def hello
p "hello Child"
super
end
end
Child.new.hello
# =>
"hello Child"
"hello Parent"
NoMethodError: super: no superclass method `hello' for #<Child:0x3eeccb0>
[Child, Parent]という順番。
Moduleをmixinする
module ModuleA
def hello
p "hello ModuleA"
super
end
end
module ModuleB
def hello
p "hello ModuleB"
super
end
end
module ModuleC
def hello
p "hello ModuleC"
super
end
end
class Parent
include ModuleA
def hello
p "hello Parent"
super
end
end
class Child < Parent
include ModuleB
include ModuleC
def hello
p "hello Child"
super
end
end
Child.new.hello
# =>
"hello Child"
"hello ModuleC"
"hello ModuleB"
"hello Parent"
"hello ModuleA"
NoMethodError: super: no superclass method `hello' for #<Child:0x4556b98>
[Child, ModuleC, ModuleB, Parent, ModuleA]という順番。
Moduleはクラスのあとに呼び出される。複数のModuleをinclude
したときは、後からinclude
されたものが先に呼び出される。
特異クラス
class Parent
def hello
p "hello Parent"
super
end
end
class Child < Parent
def hello
p "hello Child"
super
end
end
child = Child.new
def child.hello
p "hello singleton Child"
super
end
child.hello
# =>
"hello singlteon Child"
"hello Child"
"hello Parent"
NoMethodError: super: no superclass method `hello' for #<Child:0x3f0ce28>
[SingletonChild, Child, Parent]という順番。
特異クラスはクラスの前に呼び出される。
特異クラスでModuleを使う
module ModuleA
def hello
p "hello ModuleA"
super
end
end
class Parent
def hello
p "hello Parent"
super
end
end
class Child < Parent
def hello
p "hello Child"
super
end
end
child = Child.new
class << child
include ModuleA
def hello
p "hello singlton Child"
super
end
end
child.hello
# =>
"hello singlton Child"
"hello ModuleA"
"hello Child"
"hello Parent"
NoMethodError: super: no superclass method `hello' for #<Child:0x34e2f10>
[SingletonChild, ModuleA, Child, Parent]という順番。
特異クラスはクラスの前に呼び出される。またModuleはinclude
したクラスの後に呼び出される。
Module内でModuleを使う
module ModuleA
def hello
p "hello ModuleA"
super
end
end
module ModuleB
def hello
p "hello ModuleB"
super
end
end
module ModuleC
include ModuleA
include ModuleB
def hello
p "hello ModuleC"
super
end
end
class Parent
def hello
p "hello Parent"
super
end
end
class Child < Parent
include ModuleC
def hello
p "hello Child"
super
end
end
Child.new.hello
# =>
"hello Child"
"hello ModuleC"
"hello ModuleB"
"hello ModuleA"
"hello Parent"
NoMethodError: super: no superclass method `hello' for #<Child:0x393a968>
[Child, ModuleC, ModuleB, ModuleA, Parent]という順番。
Moduleはinclude
したModuleの後に呼び出される。