Ruby:获取变量名称

时间:2013-03-26 13:39:13

标签: ruby

如何获取变量名称?如,

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;

2 个答案:

答案 0 :(得分:8)

您需要执行当前变量范围的绑定,而使用the Binding class进行绑定:

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(),并在该上下文中计算变量。

答案 1 :(得分:2)

首先,您无法实现puti并直接调用puti a_var以获取a_var = value of a_var的输出。在puti的主体,Ruby只看到puti的形式参数名称,它无法推断出实际的参数名称。

在其他语言(如C / C ++)中,您可以使用Macro来实现puti。那是另一个故事。

但是,您可以在Continuation的帮助下实施put :a_var。在另一个问题“Can you eval code in the context of a caller in 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解释器将立即终止,跟踪函数无法运行。这就是最后一个“占位符”行的重点。