まず、を実装しputi
て直接呼び出しputi a_var
て、出力をとして取得することはできませんa_var = value of a_var
。の本体ではputi
、Rubyはの正式なパラメーター名のみを認識しputi
、実際のパラメーター名を推測することはできません。
C / C ++のような他の言語では、マクロを使用してを実装できますputi
。それは別の話です。
ただし、 Continuationput :a_var
を使用して、を実装できます。別の質問「Rubyで呼び出し元のコンテキストでコードを評価できますか?」では、Sony Santosがcaller_binding実装を提供して、呼び出し元のバインディングを取得します(perl呼び出し元関数など)。
callcc
ブロックが最初に戻ったときに戻り値を返すため、実装を少し変更する必要があります。Continuation
したがって、ではなくのインスタンスを取得しますnil
。更新されたバージョンは次のとおりです。
require 'continuation' if RUBY_VERSION >= '1.9.0'
def caller_binding
cc = nil # must be present to work within lambda
count = 0 # counter of returns
set_trace_func lambda { |event, file, lineno, id, binding, klass|
# First return gets to the caller of this method
# (which already know its own binding).
# Second return gets to the caller of the caller.
# That's we want!
if count == 2
set_trace_func nil
# Will return the binding to the callcc below.
cc.call binding
elsif event == "return"
count += 1
end
}
# First time it'll set the cc and return nil to the caller.
# So it's important to the caller to return again
# if it gets nil, then we get the second return.
# Second time it'll return the binding.
return callcc { |cont| cc = cont; nil }
end
# Example of use:
def puti *vars
return unless bnd = caller_binding
vars.each do |s|
value = eval s.to_s, bnd
puts "#{s} = #{value.inspect}"
end
end
a = 1
b = 2
puti :a, :b
e = 1 # place holder...
# => a = 1
# b = 2
puti
プログラムの最後のステートメントであってはならないことに注意してください。そうしないと、rubyインタープリターがすぐに終了し、トレース関数を実行できなくなります。これが最後の「プレースホルダー」行のポイントです。