LoginSignup
11
1

More than 5 years have passed since last update.

Rubyで定数が定義される場所はネスティングによって決まる

Last updated at Posted at 2018-10-10

結論

定数の定義される場所は、定義された時のネスティングによって決まる。

class_evalでクラスを開いてその中に定数を定義した際、意図した場所に定数が定義されていないことから、定数はどこに定義されるのか疑問が湧きました。


class MyClass; end

MyClass.class_eval do
  CONST = "Fuga"
end

上記のように定数を定義すると、初心者の私はMyClass::CONSTに定義されていそう!と思いました。
が、実際には、、、


pry(main)> MyClass::CONST 
#=> NameError: uninitialized constant MyClass::CONST

pry(main)> CONST
#=> "Fuga"

???Ruby何一つわからない…となってしまったのですが、定数の定義場所はネスティングによって決まるということを教えてもらい、謎が解けました。
以下、順を追って説明します。

ネスティングとは

ネスティングとは、すごくざっくり言ってしまうと"構文的な構造上のコードの区分"で(厳密な定義と間違っていたらごめんなさい)、
class識別子を使用したクラスの定義とmodule識別子を使用したモジュール定義によって切り替わり、Module.nestingによって確認できます。

class MyClass
  p Module.nesting
end

#=> [MyClass]

このネスティングに対応する位置に定数は定義されています。

CONST_TOP = "Foo"

pry(main)> p Module.nesting
#=> []
# ネスティングがトップレベルだと空

module A
  CONST_A = "Bar"
  p Module.nesting
  #=> [A] ネスティングが切り替わる

  class B
    CONST_B = "Hoge"
    p Module.nesting
    #=> [A::B, A] ネスティングが切り替わる
  end
end

pry(main)> CONST_TOP
#=> "Foo"

pry(main)> A::CONST_A
#=> "Bar"

pry(main)> A::B::CONST_B
#=> "Hoge"

#ネスティングに対応した位置に定数が定義されている!

それでは、先ほどの例に戻りclass_evalでクラスを開いて定数を定義してみると、その定数はどこに定義されるのでしょうか?


class MyClass; end

MyClass.class_eval do
  p Module.nesting
  #=> [] ネスティングは切り替わっておらず、トップレベルのまま!
  CONST = "Fuga"
end

# class_evalのブロックの中に入ってもネスティングは切り替わっておらず、トップレベルのまま。
# ということは、定数CONSTはトップレベルのネスティングの位置に定義されているはず!

pry(main)> CONST
#=> "Fuga"
# なるほど〜

MyClass::CONSTに定数が定義されているのでは?と思ってしまうのは、class_evalを使うとコンテキストがMyClassに切り替わっているためなんですね…


MyClass.class_eval do
  p self
  #=> MyClass
  # コンテキストがMyClassに切り替わるため(selfがMyClassに切り替わるため)、
  # 見た目的にMyClass::定数名の位置に定数が定義されていると勘違いしてしまった…
end

まとめ

定数の定義場所はネスティングによって決まる(コンテキストは関係無い)ため、定数を定義する際はネスティングに注意しよう!という話でした。

参照
rubyリファレンスマニュアル
メタプログラミングRuby

11
1
9

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
11
1