rubyの class_eval とスコープのメモ

rubyのclass_evalは「ブロックをクラス定義やモジュール定義の中のコードであるように実行します。ブロックの戻り値がメソッドの戻り値になります。」と書いてますが、次の例は以下のような警告がでるようです。

warning: class variable access from toplevel

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  @@a = 1
}

A.a

どうも class_evalのブロック中で @@aはクラスAの@@aを見ているのではなくトップレベルに @@aという変数を定義してしまっているようです。

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  @@a = 1
}

p @@a #=>1

これを期待したように実行するには

class_variable_set

を使うとよいようです。

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  class_variable_set :@@a, 1
}

A.a

あるいは class_evalの中身を文字列で渡してしまえばOK

class A
  def self.a
    p @@a
  end
end

A.class_eval <<-EOS
  @@a = 1
EOS

A.a