🎉
Ruby の .class_eval でクラス変数は参照できない?
例えばクラスのインスタンス変数は以下のように .class_eval
経由で参照することができます。
class X
@value = 42
end
pp X.class_eval { @value }
これと同じ様にしてクラス変数にアクセスしようとしたらエラーになりました。
class X
@@value = 42
end
# error: class variable access from toplevel (RuntimeError)
pp X.class_eval { @@value }
これだとトップレベルでクラス変数を参照しようとしてエラーになっているんですよね。
なので試しに他のメソッドから呼ぶようにしてみたら
class X
@@value = 42
end
class Y
@@value = -1234
def hoge
X.class_eval {
# これは Y のクラス変数を参照する
@@value
}
end
end
pp Y.new.hoge
# => -1234
って感じでクラス変数は .class_eval
のコンテキスト内に依存するのではなくて呼び出しもとのコンテキストに依存するぽいんですよね。
なので動的にメソッドを定義する際にうっかりクラス変数を参照すると意図しない挙動になります。
class X
@@value = 42
end
class Y
@@value = -1234
def hoge
X.define_method(:foo) {
# 本来は X のクラス変数を参照したいが、実際にや Y のクラス変数を参照してしまっている
@@value
}
end
end
Y.new.hoge
pp X.new.foo
# => -1234
クラス変数自体そもそも使わないほうがいいんですが、これは知らなかった。
どうしてもクラス変数を参照したい場合は以下のように .class_variable_get
を経由すると取得することができます。
class X
@@value = 42
end
class Y
@@value = -1234
def hoge
X.define_method(:foo) {
X.class_variable_get(:@@value)
}
end
end
Y.new.hoge
pp X.new.foo
# => 42
Discussion