さくらんぼのlambda日記

lambdaちっくなことからゲーム開発までいろいろ書きます。

mainとか局所変数とかクロージャとかどうなっとるんじゃー!

Rubyが気持ち悪いです。

#この変数の所属は?
@var1 = 10
var1 = 10

#ここに居るらしい。
p local_variables
#p global_variables
#p self.instance_variables


def hoge 
  puts "main hoge called"
end

class Test
  def initialize
    @moga = 1
  end
  def hoge
    puts "class hoge called"
  end
  attr_accessor :moga
end


Test.__send__(:define_method, :fuga ) do
  #ここにも居る。do - endはそれが作られた時点での束縛を保存するようだ。
  #しかし、評価はそれが評価されるときのコンテキスト
  #なのでvar1と@mogaの両方が混在できる不思議な状況になる。
  p local_variables
  @moga = var1
  hoge
end

Test.new.fuga
hoge

答え define_method + ブロックは気持ち悪いです。
これでいてdefine_methodが評価されるのは、そのブロックが評価される場合の
コンテキストで評価されます。上記の例ではTestの中に居る状況で評価が行なわれます。


この件に関してはdefine_methodのマニュアルにも載っています。

ブロックを与えた場合、Ruby 1.7 以降では、定義したメソッドの実行時にブロックがレシーバクラスのインスタンスの上で instance_eval されます。一方 Ruby 1.6 ではブロックとメソッドの関連づけを行うだけで、メソッドの実行時にはブロックは生成時のコンテキストのままで実行されます。たとえば以下の例を参照してください。

class C
  def print_self
    p get_self
  end
end
# インスタンスメソッド get_self を定義。
# ただし define_method はプライベートメソッド
# なので直接は呼べない。__send__ を介して呼ぶ。
C.__send__(:define_method, :get_self) { self }

# 1.6 の場合
C.new.print_self    #=> main
# 1.7 の場合
C.new.print_self    #=> #<C:0x4015b490>

正直どうでもいいですよねw