Ruby

class_eval の中で定数を定義したときのスコープ

この記事はOkinawa.rb Advent Calendar 2018の16日目の記事です。

class_eval の中で定数を定義したときのスコープですが、オープンクラスしたときと違ってブロックの外側のスコープで定義されます。


class_eval {|mod| ... } -> object

ブロックが与えられた場合には、定数とクラス変数のスコープはブロックの外側のスコープになります。

https://docs.ruby-lang.org/ja/2.5.0/method/Module/i/class_eval.html


オープンクラスの場合

class Foo

end

class Foo
BAR = 'baz'
end

puts Foo::BAR

$ ruby foo.rb

baz

class_eval の場合

class Foo

end

Foo.class_eval do
BAR = 'baz'
end

puts Foo::BAR

Ruby 2.4 までは警告が出るものの実行できます。

$ ruby foo.rb

foo.rb:8: warning: toplevel constant BAR referenced by Foo::BAR
baz

Ruby 2.5 以上だとエラーになります。


Ruby 2.5.0 リリース

トップレベルの定数検索は削除されました。[Feature #11547]

https://www.ruby-lang.org/ja/news/2017/12/25/ruby-2-5-0-released/


$ ruby foo.rb

Traceback (most recent call last):
vending_machine2.rb:8:in `<main>': uninitialized constant Foo::BAR (NameError)
Did you mean? BAR