こんばんは、Tsugohです。


>>> Quoted from "[ruby-list:36119] Re: 閉じた binding"
>>>   ( on 2002/10/07 0:30:06 JST / by UENO Katsuhiro )

>ええと、僕も同じようなことを考えて書いたコードがあります。
>  http://www.blue.sky.or.jp/atelier/ruby/wakaba/wakaba-0.1.0.tar.gz
>の中の lib/wakaba/pbinding.rb ってファイルです。

参照させて頂きました。

なるほど…、特異クラスを作り、その中で、メタ機能により削除可能な定数を経由して
ローカル変数を生成するという方法なんですね。
こんなやり方があったとは、目から鱗が落ちます。


参考にさせて頂いた上でとりあえず簡易版を作ってみました。

  def protected_binding( params = {} )
    raise ArgumentError  unless Hash === params
    klass = class << self; self; end
    klass.module_eval 'def jail_binding; binding; end'
    
    b = jail_binding
    
    unless params.empty? then
      carrier = :Variables
      klass.module_eval { const_set carrier, params }
      eval params.keys.collect{ |k| "#{k}=#{carrier}[#{k.dump}];" }.join, b
      klass.module_eval { remove_const carrier }
    end
    
    klass.module_eval {
      remove_method :jail_binding
      const_set :TOPLEVEL_BINDING, b
    }
    
    b
  end

  hash = { 'foo' => 'foo', 'bar' => 100, 'baz' => Proc.new{nil} }
  eval 'p local_variables.collect{|v| [v, eval v]}',
        protected_binding( hash )
  # => [["baz", #<Proc:0x2acce8c4>], ["foo", "foo"], ["bar", 100]]

あとは Wakaba::ProtectedEval の様に、ローカル変数として使える key を
チェックしたり Symbol も使えるようにすればかなり奇麗になりそうです。


ただ、ソースを読ませて頂いていて二つほどわからないことがありました。

1) protected_binding の最後で
     klass.module_eval{ :TOPLEVEL_BINDING, b }
   とされているのはどういう理由なんでしょうか?
   勉強不足のため理解できていません(汗)
   (簡易版ではわからないままに付けています(^^;)

2) Wakaba::ProtectedBinding で
     carrier << '_' while parameters.key? carrier
   としていますが、これも理解できてません(汗)
   (簡易版では省いてみました。)

もしよろしければお返事をお願いします。


# もし他にも方法がありお時間に余裕があれば、皆さん是非ご教授ください。
# 勉強させて頂きます(^^;;

-----
Tsugoh
mailto:tks / xxxx-xx.xx