Ruby のトップレベルメソッドって結局なんなの

以下のような質問があったのでちょっと解説。

トップレベルメソッドを理解するためには、以下の3つの Ruby の機能について理解する必要があります。

self ってなに

まず、トップレベルメソッドを理解する前に『 self とは何か』を知る必要があります。
self とはメソッド内で『メソッドを呼び出したレシーバ』を参照するキーワードになります。
また、レシーバとは『メソッド呼び出しの左辺のオブジェクト』を指します。

class X
 def foo
  "foo"
 end

 def hoge
  # meth を呼び出したレシーバを参照する
  pp self
  # => #<X:0x00005627e8a8a050>

  # レシーバ、つまり x の foo メソッドを呼び出す
  pp self.foo
  # => "foo"
 end
end

x = X.new

# メソッドを呼び出す際に左辺にあるオブジェクトの事を『レシーバ』という
# この場合は x オブジェクトがレシーバに該当する
x.hoge

また、レシーバをつけずにメソッドを呼び出した場合は暗黙的に『self をレシーバとして』メソッドを呼び出します。

class X
 def foo
  "foo"
 end

 def hoge
  # レシーバがなければ self のメソッドを呼び出す
  # self.foo と等価
  pp foo
  # => "foo"
 end
end

トップレベルって?

そもそも『Ruby のトップレベルって何?』っていう話なんですが、Ruby では『classmodule の中で定義していないメソッド』がトップレベルメソッドに該当します。

# class や module 内で定義していないメソッド
def topleve_method
 "topleve_method"
end

class X
 # これは X のインスタンスメソッドなのでトップレベルではない
 def meth

 end
end

また、トップレベルでも self は存在し、トップレベルで self を呼び出した場合、 main という名前のオブジェクトを返します。

pp self
# => main

main はトップレベルで定義されている特別なオブジェクトになります。

トップレベルでメソッドを定義するとどうなるの?

トップレベルでメソッドを定義した場合、暗黙的に『Object クラスの private メソッド』として定義されます。
どういうことかというと

def hoge
 "hoge"
end

というトップレベルメソッドは、

class Object
 private
 def hoge
  "hoge"
 end
end

という定義と等価になります。
ちなみに Ruby における private とは『レシーバをつけて呼び出すことが出来ないメソッド』になります。

class X
 # hoge を private メソッドとして定義する
 private
 def hoge
 end

 def foo
  # OK : レシーバをつけずに呼び出す
  hoge

  # NG : self もつけて呼び出すことは出いない
  self.hoge
 end
end

x = X.new

# NG : レシーバをつけて呼び出すことは出来ない
x.hoge

Object クラスって何

Object クラスは『全てのクラス』が継承しているクラスになります。
例えば StringArray といった組み込みクラスやユーザが定義したクラスも暗黙的に Object クラスを継承しています。

# Module#< で任意のクラスを継承しているかチェックする

# 組み込みクラスは Object を継承している
p String < Object
p Array < Object

# ユーザが定義したクラスも暗黙的に Object を継承している
class X
end
p X < Object

つまり 『トップレベル定義したメソッド= Object クラスの private メソッド』は『 Object を継承しているクラス=全てのクラス』の『private メソッド』として参照できます。

# Object の private メソッドとして定義される
def hoge
 "hoge"
end

class X
 def foo
  # Object は親クラスなので
  # 親クラスの private メソッドが呼べる
  hoge
 end
end

x = X.new
p x.foo
# => "hoge"

# NG : private メソッドなので直接呼べない
# p "foo".hoge

# OK : send だと private メソッドも明示的に呼べる
p "foo".send(:hoge)
# => "hoge"

結局トップレベルでメソッドって?

  • トップレベルでメソッドを定義すると Object のメソッドとして定義される
  • Object は全てのクラスが継承しているのでどのクラスからでも呼び出せる
  • 当然トップレベルの self(= main)も Object クラスを継承しているのでトップレベルでも呼び出せる
  • main とトップレベルメソッドは特に関連はない

トップレベルの selfmain っていう特別なオブジェクトなので、どうしてもそっちの方に意識が向くんですが、トップレベルの self とトップレベルのメソッドは特に関連性はありません。
まずは、『トップレベルメソッド』というのが先にあり、『main』っていうのが後にあります。
ちなみに『トップレベルメソッド』の他に『トップレベル定数』というものがありトップレベル定数はトップレベルメソッドの100000万倍ぐらいややこしい仕様なので知らないほうがいいです。