Mae向きなブログ

Mae向きな日記のブログ版。ようやくこちらに移行してきました。

メタプログラミングRuby -- 第3章

メタプログラミングRuby』の第3章まで読み終えました。まだ途中ですが,いろいろと刺激を与えてくれる本で,難しいところもありますが,わくわくドキドキしながら読み進めています。
第3章の最後に紹介されている,blocks/monitor_final/redflag.rb なんかは,じっくり考えると納得できますが,果たして自分がこんな風に書けるようになるんだろうかとも思います。
第3章の復習を兼ねて,以下を作ってみました。実行結果を予測できますか?

chap3_test.rb

#!/usr/bin/env ruby

#########################
# (1)
lambda {
  @str = "Hello, Ruby(1)"
  def hello1
    puts @str
  end
}.call

hello1

#########################
# (2)
lambda {
  str = "Hello, Ruby(2)"
  Kernel.send :define_method, :hello2 do
    puts str
  end
}.call

hello2

#########################
# (3)
lambda {
  str = "Hello, Ruby(3)"
  def hello3
    puts str
  end
}.call

hello3

解説?

(1)は,トップレベルのインスタンス変数@strを使ってます。mainがselfになる場所であればどこからでも呼び出せるので実行できます(p114参照)。
(2)は,strはローカル変数ですが,Module#define_methodを使うことで,スコープゲートを超えて,strをhello2に渡すことができるので実行できます(p116参照)。
(3)は,strはローカル変数で,hello3からのスコープを外れて見えなくなるため実行できません。一見,hello3から外側のstrは見えるような気がしますが,Rubyにはこうした可視性の入れ子構造は存在せず,スコープはきちんと区別されているそうです(p113参照)。