How can I get a variable name? E.g.,
def get_var_name(var)
# return variable name
end
myname = nil
get_var_name myname #=> myname
Initial purpose:
somevar = "value"
puti somevar #=> somevar = "value"
# that is a shortage for
# `puts "somevar = #{somevar.inspect}"`
My try:
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;
You need to carry across the binding of the current variable scope, which you do 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 which remembers the context at the point the method was called. You then pass a binding into eval()
, and it evaluates the variable in that context.
First, you cannot implement a puti
and directly call puti a_var
to get the output as a_var = value of a_var
. At the body of puti
, Ruby sees only the formal parameter names of puti
, it cannot infer the actual parameter names.
In some other language like C/C++, you can use Macro to implement your puti
. That's another story.
However, you can implement put :a_var
, with the help of Continuation. In another question "Can you eval code in the context of a caller in Ruby?", Sony Santos has provided a caller_binding implementation to get the binding of the caller (something like the perl caller function).
The implementation should be altered a bit, because callcc
returns the return value of the block at its first returning. So you'll get an instance of Continuation
rather than 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'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
Note the puti
should not be the last statement of your program, otherwise the ruby interpreter will terminate immediately and the trace function has no chance to run. So that's the point of the last "place holder" line.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With