2009-08-12 [長年日記]

_ [ruby] 定数の探索経路

あなたの Ruby コードを添削します 【第 3 回】 dbf.rb を参考にして、DSL を処理する部分を書いてるんだけど、ネストしたモジュールの下に DSL の記述を持ってくると、外部で定義したクラスが見えなくてちょっとハマる。1.8 だと動くのが何とも。

RUBY_DESCRIPTION # => "ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]"

class C
  class << self
    def m(&b)
      Class.new(self) do |c|
        c.class_eval(&b)
      end
    end
  end
end

C1 = C.m{}
C2 = C.m{
  self # => #<Class:0xb7c9d6ac>
  C1   # => C1
}

module M
  module M1
    C3 = C.m{}
  end

  module M2
    include M1
    C4 = C.m{
      self # => #<Class:0xb7c9d0a8>
      C3   # => M::M1::C3
    }
  end
end

C.m が PackedStruct.define というイメージ。1.8 だとこれでうまくいくんだけど、

RUBY_DESCRIPTION # => "ruby 1.9.2dev (2009-08-11 trunk 24495) [i686-linux]"

class C
  class << self
    def m(&b)
      Class.new(self) do |c|
        c.class_eval(&b)
      end
    end
  end
end

C1 = C.m{}
C2 = C.m{
  self # => #<Class:0x98d184c>
  C1   # => C1
}

module M
  module M1
    C3 = C.m{}
  end

  module M2
    include M1
    C3     # => M::M1::C3
    C4 = C.m{
      self # => #<Class:0x98d0ed8>
      C3   # =>
    }
  end
end
# ~> -:29:in `block in <module:M2>': uninitialized constant #<Class:0x8422004>::C3 (NameError)
# ~>    from -:7:in `class_eval'
# ~>    from -:7:in `block in m'
# ~>    from -:6:in `initialize'
# ~>    from -:6:in `new'
# ~>    from -:6:in `m'
# ~>    from -:27:in `<module:M2>'
# ~>    from -:24:in `<module:M>'
# ~>    from -:19:in `<main>'

1.9 だとうまくいかない。だいぶ悩んだけど、

-        c.class_eval(&b)
+        c.class_eval{b.call}

に変えたらいけた。こうすると C.m{} 内の self が main やら M::M2 になってうまくいくみたい。まだ理解しきれてないけど、とりあえず日記書くと色々解決する。

追記: と思ったら、これでは C のクラスメソッドとして用意してる DSL 用のメソッドが見えないぉ。目的を見失ってるぉ。

[]

«前の日記(2009-07-31) 最新