2016-05-09 1 views
2

親スコープ内の変数を設定するには、ブロックを使用して、便利ですが、文字列内の変数の初期化をすべて行う必要があるため制限されています。は宝石<a href="https://github.com/banister/binding_of_caller" rel="nofollow"><code>binding_of_caller</code></a>が親スコープで変数を設定する方法についての例があり

私は少し考えて、YAMLを使ってオブジェクトをシリアライズ/デシリアライズすることができることに気付きました。

テイク、例えば、次の例:

def c 
    value = YAML.dump [ { a: "b" } ] 
    binding.of_caller(2).eval("var = YAML.load('#{value}')") 
end 

a() 
# => {a: "b"} 

これはクールですが、私は完全に直列化を回避し、ちょうどそのような適切なdo; end;ブロック書くことができれば、それが良いだろう:

# doesnt work 
def c 
    binding.of_caller(2).eval do 
    # ideally this would set the variable named "var" in the scope of method "a" 
    var = [ { a: "b" } ] 
    end 
end 

この最後の例の機能をどのように達成できますか?別の方法がある場合はbinding_of_callerを使用する必要はありません。

+0

質問がありますか? –

+0

@Jordan明示的な質問を追加しました –

答えて

4

これは私が何ができる最善であると、私は、(私は本当に間違って証明するのが大好きですが)あなたは、LA binding_of_callerを独自のC拡張を書くの短い見つける最高の疑い:

require 'binding_of_caller' 

module BindingExtensionEvalBlock 
    def eval_block(&block) 
    eval("ObjectSpace._id2ref(%d).call(binding)" % block.object_id) 
    end 
end 

class ::Binding 
    include BindingExtensionEvalBlock 
end 

魔法はもちろん、ここにある:

eval("ObjectSpace._id2ref(%d).call(binding)" % block.object_id) 

我々はを渡し、それがメモリ内にあるどこからそれを取得し、それを呼び出すためにObjectSpace#_id2refを使用して、私たちのBinding#evalで、その後、PROCのオブジェクトIDを取得し、ローカルbinding

は、ここでは、アクションである:

def a 
    var = 10 
    b 
    puts var 
end 

def b 
    c 
end 

def c 
    binding.of_caller(2).eval_block do |bnd| 
    bnd.local_variable_set(:var, [ { a: "b" } ]) 
    end 
end 

a # => {:a=>"b"} 

あなたが見ることができるように、代わりのvar = [ { a: "b" } ]私たちのブロックに我々はbnd.local_variable_set(:var, [ { a: "b" } ])を行う必要があります。 Rubyでのブロックのバインディングを変更する方法はないので、バインディング(bnd)を渡してBinding#local_variable_setと呼ぶ必要があります。

関連する問題

 関連する問題