2012年2月14日

[ruby-list:48620] eval の中で定数定義

今井と申します。

言語仕様の質問なのですが、
eval で、定数を定義する文をコンパイル・実行しようとするとどうなるでしょうか。

例えばこのような場合です。
class A
def f

eval %"
C1 = 1
class C2
end
", binding
end
end
a = A.new
a.f

このように、メソッドの中で実行される eval に渡すコード(の直下)で
定数を定義するのは
 ・合法なのか
 ・合法なら、定数はどのモジュール(orクラス)に定義されるのか
  (定数が定義される対象のモジュールorクラスはどうやって決まるのか)
この2点、リファレンスマニュアルを読んでも答えが得られませんでした。
(見落としならごめんなさい)

合法かどうかは、
おそらく合法なんだろうと思いますが、マニュアルからは読み取りにくいです。
マニュアルの「変数と定数」のページには
>定数の定義 (と初期化) は代入によって行われますが、メソッドの中では定義できません。
とあり、メソッドの中の eval で解釈される文字列の中の場合にどうなのかは
わかりにくいです。
「Ruby プログラムの実行」「Kernel.#eval」などの項を見ても解決しません。


手元の ruby 1.8.7 で試すと、
(上のコードの後で)
p C1 #=> uninitialized constant C1 (NameError)
p A::C1 #=> 1
p A::C2 #=> A::C2
クラス A に定義されているようです。

ついでに他の場合も試すと
a.instance_exec{ eval "C3 = 3" }
p C3 #=> 3
# トップレベルに定義されたらしい

class A
def g
instance_eval "C4 = 4"
end
end
a.g
p A::C4 #=> エラー
p( (class << a ; self ; end )::C4 ) #=> 4
# a の特異クラスに定義されたらしい

この挙動からすると、定数の定義&探索については、
 ・eval の場合は Binding オブジェクトが持つモジュールネスト構造(静的スコープ)
  の最内側モジュールの直下と同様になる
 ・文字列をとる instance_eval の場合は 特異クラス定義文の中と同様になる
といったことかなと推測しています。

背景としては、ruby を使ってとあるツールを作っており、
上のような振る舞いを言語の仕様と見なして利用してしまってよいかどうかを
確認したいです。


----
Rintaro IMAI


投稿者 xml-rpc : 2012年2月14日 19:26
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/108591
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。