この説明の大部分は、James Coglan によるHow Ruby Method Dispatch Worksに基づいています。Ruby Hacking Guideの一部と、ソースのほんの一部です。
要約すると、祖先は次のようになります。
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
---> Parent
~~~> Singleton class
最初から始めて構築しましょう。BasicObject
はすべてのルートです。チェックするBasicObject.superclass
と、 が得られnil
ます。BasicObject
のインスタンスでもありますClass
。はい、それは循環します。コードにはそれを処理する特別なケースがあります。A
が のインスタンスである場合、B
はA.singleton_class
の子であるため、次のB
ようになります。
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
から継承しBasicObject
ます。A
から継承する場合B
、A
は の子でB
ありA.singleton_class
、 の子ですB.singleton_class
。Object
も含まれKernel
ます。A
が含まれている場合B
、は(それ自体の後、 の前に)B
の最初の祖先として挿入されます。A
A
A.superclass
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
のインスタンスですModule
。これは私たちが目にする唯一のインスタンスでModule
あり、そのシングルトン クラスはどの祖先チェーンにも表示されないため、それ以上の説明はしません。
これはFoo
から継承されObject
ます (ただし、 と書く必要はありません< Object
)。何Foo
とそのシングルトン クラスの子であるかは、既に把握できています。
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Class
が から継承されModule
、 が からModule
継承されるようになったため、と適切なシングルトン クラスObject
を追加します。ととModule
、これは図面が少しファンキーになる場所です。をヒットするたびに、上へのトラバースを停止することを忘れないでください。Module < Object
Object < BasicObject
BasicObject.instance_of?(Class)
BasicObject
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ |
| | |
| BasicObject ~~~~~> #<Class:BasicObject> |
| ^ ^ |
| | Kernel | |
| | ^ | |
| | | | +----------------------------------------+
| +-----+----+ | |
| | | v
+-------> Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
最後のステップ。のすべてのインスタンスにClass
は がありますsingleton_class
(ただし、必要になるまでインスタンス化されません。そうしないと、より多くの RAM が必要になります)。シングルトン クラスはすべて のインスタンスでClass
あるため、シングルトン クラスがあります。次の文に注意してください: クラスのシングルトン クラスの親は、クラスの親のシングルトン クラスです。型システムに関する限り、それを簡潔に述べる方法があるかどうかはわかりませんが、Ruby のソースは、どのような場合でも一貫性のためにそれを行っているだけだと言っています。したがって、 を要求するFoo.singleton_class.singleton_class
と、言語は喜んで義務付け、必要な親を上に伝播し、最終的には次のようになります。
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
このグラフの任意のノードから開始し、深さ優先で右から左にトラバースすると (そして で停止するとBasicObject
、希望どおりにノードの祖先チェーンが得られます。そして、いくつかの基本的な公理から構築したので、信頼が欠けている場合、構造をさらに検証する興味深い方法がいくつかあります。
node.singleton_class.ancestors - node.ancestors
グラフ内の任意のノードを探してみてください。これにより、ノード自体の祖先ではないシングルトン クラスの祖先が得られ、リスト内の紛らわしい冗長性の一部が排除されます。
> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
=> [#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>,
#<Class:Class>, #<Class:Module>]
を使用して、任意の 1 つの親を確認することもできますnode.superclass
。
> Foo.singleton_class.singleton_class.superclass
=> #<Class:#<Class:Object>>
また、オブジェクト ID がすべて一貫していることを確認することもできるため、互いに特定の関係を持たない匿名クラスがいたるところに出現することはありません。
> def ancestor_ids(ancestors)
> ancestors.map(&:object_id).zip(ancestors).map{|pair| pair.join("\t")}
> end
> puts ancestor_ids(Foo.ancestors)
70165241815140 Foo
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.ancestors)
70165241815120 #<Class:Foo>
70165216039400 #<Class:Object>
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object # Same as Foo from here down
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.singleton_class.ancestors)
70165241980080 #<Class:#<Class:Foo>>
70165215986060 #<Class:#<Class:Object>>
70165215986040 #<Class:#<Class:BasicObject>>
70165216039440 #<Class:Class>
70165216039420 #<Class:Module>
70165216039400 #<Class:Object> # Same as Foo.singleton_class from here down
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
そして、一言で言えば、それはあなたがオタクを狙撃する方法です.