トップオブジェクトが持つClassを全部表示する方法

よくrequire()してコードを書いていると、今いる階層にはどんなクラスが存在するのか
一覧を見てみたくなりませんか?
実は、id:akio0911に「Rubyでクラス一覧を表示する方法知らない?」と聞かれたので
調べてみました。

答え

self.class.constants.reject{|constant| eval("!#{constant}.kind_of?(Class)")}

・・・えーと。はい。よくわからないと思うのでもう少しわかりやすく書きます。

self.class #=> Object

トップオブジェクトのクラスを返してもらいます。

self.class.constants #=> ["TrueClass", "CROSS_COMPILING", ... ]

トップオブジェクトが持つコンスタンスを配列として返してもらいます。
この配列の中には、トップオブジェクトが所持する定数、クラス、モジュールのすべてが
格納されています。

self.class.constants.reject{|constants| <条件式> }

<条件式> を満たすものを配列から除外します。
今回の場合は、「クラス一覧を表示」したいので、クラス以外を除外します。

なので、条件式は

eval("!#{constant}.kind_of?(Class)")

と、なります。

詳しく解説すると、eval(String)というのは
与えられた文字列をRubyの実行文として実行するという一風変わったメソッドです。
ここで与えられた内容は、

"!#{constant}.kind_of?(Class)"

ですね。

これをさらに詳しく解説すると、Object.kind_of?(Class)というのは
Objectが与えられたClassと等しいか?をtrueかfalseで返します。
ここでは#{constant}というなぞのオブジェクトを示していますが
これはブロックに与えられたconstant変数を示しますね。
気をつけてほしいのは、先頭についてる「!」です。
これは、ビット反転といって、trueならfalseに、falseならtrueとして解釈するという
天邪鬼な代物です。
つまり、!Object.kind_of?(Class)という場合は
ObjectがClassと等しい場合はtrue・・・の反対「false」となります。

結果としては、トップオブジェクトが持つクラスを全部表示してくれるわけですね。

ちなみに

self.class.constants.reject{|constant| eval("!#{constant}.kind_of?(Module)")}

このようにすると、トップオブジェクトが持つモジュールを全部表示してくれます。

いろんなコードやライブラリをrequireしすぎて、今どのクラスがあるのかわからなくなった
ときには便利かもしれませんね。