LoginSignup
3
0

More than 3 years have passed since last update.

トップレベルで定義したメソッドは全クラスのプライベートメソッドとなる

Last updated at Posted at 2020-01-22

イントロダクション

西遊記より
孫悟空にお釈迦様は言われます「私の掌から飛び出すことができれば、お前を自由にしてやる」。悟空は筋斗雲に飛び乗り世界の端を目指します。ここまで来たら大丈夫だろうとそこの山に「悟空参上!」と書きました。お釈迦様に報告した所、お釈迦様の掌にはその文字が書いてありました。

一見奇妙なコード

ある日、肥大化したクラスをリファクタリングしようと処理を分割していた時、不思議な現象に遭遇しました。

class Hoge
  def execute
    @str = "Hello Ruby!"
    hello
  end
end

def hello
  puts @str
end

hoge = Hoge.new
hoge.execute
# => Hello Ruby!

このコードは問題なく動作して「Hello Ruby!」を出力します。
しかしなぜ分離独立している筈のhelloメソッド内部でHogeクラスのインスタンス変数strを参照できているのでしょうか?他の言語ならエラーになりそうなのに。

何がおきているのか

まずRubyのトップレベルに書いたメソッドがどこに定義されるのかというとKernelモジュールのprivateに定義されます。
(追記:コメントにて指摘されていますが、正しくはObjectに定義されます)

p Kernel.private_methods
# => [:hello, ...]

helloメソッドが追加されていることが確認できます。
このKernelモジュールはObjectクラスにてインクルードされ、さらにすべてのクラスはObjectを継承します。
この関係を確認してみましょう。

p Hoge.ancestors
# => [Hoge, Object, Kernel, BasicObject]

ここまで来ればHogeクラスにもhelloメソッドが定義されていることに気が付くでしょう。

p Hoge.private_methods
# => [:hello, ...]

結論

トップレベルで定義したメソッドは全クラスのプライベートメソッドとなる
helloメソッドはHogeクラスから分離独立しているように見えるが、実際は内部に定義されていたのです。だから普通にインスタンス変数にもアクセスできたのです。
Rubyの基礎階層を理解していないと孫悟空の様にホワッ?となるエピソードでした。

3
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0