10

変数名を取得するにはどうすればよいですか?例えば、

def get_var_name(var)
  # return variable name
end

myname = nil
get_var_name myname #=> myname

当初の目的:

somevar = "value"

puti somevar #=> somevar = "value"
# that is a shortage for
# `puts "somevar = #{somevar.inspect}"`

私の試み:

def puti(symb)
  var_name  = symb.to_s
  var_value = eval(var_name)
  puts "#{var_name} = #{var_value.inspect}"
end
puti :@somevar # that actually will work only with class vars or whatever considering var scope;
4

2 に答える 2

8

現在の変数スコープのバインディングを引き継ぐ必要があります。これは、Bindingクラスで行います。

def puti(symb, the_binding)
  var_name  = symb.to_s
  var_value = eval(var_name, the_binding)
  puts "#{var_name} = #{var_value.inspect}"
end

somevar = 3

puti :somevar, binding   # Call the binding() method

   #=> outputs "somevar = 3"

このbinding()メソッドは、メソッドが呼び出された時点でのコンテキストを記憶するBindingオブジェクトを提供します。次に、バインディングをに渡し、eval()そのコンテキストで変数を評価します。

于 2013-03-26T14:03:20.173 に答える
2

まず、を実装し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インタープリターがすぐに終了し、トレース関数を実行できなくなります。これが最後の「プレースホルダー」行のポイントです。

于 2013-03-26T14:43:40.240 に答える