ruby 2.5で変更されたtoplevel constant lookupの挙動

こういうコードがあったとして

class Foo; end
class Bar; end
p Foo::Bar #=> Bar

ruby 2.4まではwarning: toplevel constant Bar referenced by Foo::Bar を出しつつFoo::BarBarを返す。

これはrubyの定数探索が継承関係を遡って探すという仕様と、トップレベルで定義された定数がObjectに所属する、という仕様によるもの。わかりやすく書くとこういう感じ。

class Foo < Object; end
Object::Bar = 1
p Foo::Bar #=> 1

Foo::BarとしたときFooにはBarがないので、次にFooの継承関係を辿って親クラスのObjectからBarを探す。するとObject::Barが見つかるのでObject::Barを返す。

2.5だとこれがエラーになるように変更された。

class Foo; end
class Bar; end
p Foo::Bar #=> NameError: uninitialized constant Foo::Bar

ref: https://bugs.ruby-lang.org/issues/11547