Ruby: getting a variable name

How to get the variable name? For example.

def get_var_name(var) # return variable name end myname = nil get_var_name myname #=> myname 

Original goal:

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

My attempt:

 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; 
+8
ruby
Mar 26 '13 at 13:39
source share
2 answers

First, you cannot implement puti and directly call puti a_var to get the output as a_var = value of a_var . Ruby sees only puti formal parameter names in the puti ; it cannot display the actual parameter names.

In some other language, such as C / C ++, you can use Macro to implement your puti . This is another story.

However, you can implement put :a_var with Continuation . In another question, β€œ Can you use the eval code in the context of the caller in Ruby? Sony Santos provided caller_binding to get the caller's binding (something like a perl call function).

The implementation should be slightly modified because callcc returns the return value of the block when it is first returned. This way you get an instance of Continuation , not nil . Here is the updated version:

 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 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 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 

Please note that puti should not be the last statement of your program, otherwise the ruby ​​interpreter will puti immediately and the trace function will not have a chance to run. So the point of the last line is "owner's place".

+2
Mar 26 '13 at 14:43
source share

You need to transfer the binding of the current variable area that you are doing with 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" 

The binding() method gives a binding object that remembers the context at the method call point. Then you pass the binding to eval() and it evaluates the variable in that context.

+8
Mar 26 '13 at 14:03
source share



All Articles