2010-07-14 20 views
8

Al desarrollar & depuración, a veces me gustaría poder escribir un 1-liner que arrojó los nombres, tipos & valores de un grupo de variables. El problema es que no sé cómo acceder al nombre de una variable, si es que puedo.Obtener el nombre de una variable local

Aquí es un primer intento:

foo = 1 
bar = "42" 
baz = Hash.new 

[foo, bar, baz].each do |v| 
    puts "#{v.???} = (#{v.class}) #{v}" 
    end 

me gustaría la salida de este programa a ser algo así como:

foo = (Fixnum) 1 
bar = (String) 42 
baz = (Hash) ... 

No sé lo que ??? debe estar por encima. Se puede hacer esto?

+0

Podría invertir su lógica e irse con la solución de Glenn: http://stackoverflow.com/questions/58482/ruby-get-a-variables-name Tengo entendido que no puede obtener el nombre de una variable. – Pat

+0

@Pat: Esto es en efecto lo mismo que la solución de Leventix, pero con una sintaxis diferente. Así que supongo que la respuesta es sí. :) –

+0

No estoy seguro si exemplor puede manejar múltiples variables, pero exemplor le permite llamar 'Show (variable)' le da el nombre de la variable y su valor. http://github.com/quackingduck/exemplor –

Respuesta

13
foo = 1 
bar = "42" 
baz = Hash.new 

%w(foo bar baz).each do |vn| 
    v = eval(vn) 
    puts "#{vn} = (#{v.class}) #{v}" 
end 

Pero esto, por supuesto, no lo ayuda si quiere un método con 1 argumento.

+0

Brillante! ¡Gracias! Ojalá pudiera votar esto dos veces. –

+2

acabo de encontrar una solución muy fresco para esto: http://thinkrelevance.com/blog/2009/09/23/quick-and-easy-logging-with-logbuddy.html – Leventix

3

No, porque foo/bar/baz no son variables de instancia en su código. Son variables locales (las variables de instancia comienzan con @). Hay una manera de hacerlo con las variables de instancia y el método Object#instance_variables, sin embargo:

@foo = 1 
@bar = 2 
@baz = 3 

instance_variables.each do |var| 
    value = instance_variable_get var 
    puts "#{var} = (#{value.class}) #{value}" 
end 

# outputs: 
# @foo = (Fixnum) 1 
# @bar = (Fixnum) 2 
# @baz = (Fixnum) 3 

para obtener el nombre de una variable de instancia particular, recorrer todos las variables de instancia hasta que encuentre uno con un valor que coincide su variable de instancia.

4

Aquí hay un poco de código de depuración que uso en todas partes (lo incluyo en un archivo aparte para que pueda ser necesario donde sea necesario). Se puede usar de dos maneras. Pasó uno o más valores, simplemente los inspecciona y escribe el resultado en $ stderr. Pero pasado un bloque que devuelve una o más cosas, que las escribe con sus nombres.

#!/usr/bin/ruby1.8 

def q(*stuff, &block) 
    if block 
    s = Array(block[]).collect do |expression| 
     value = eval(expression.to_s, block.binding).inspect 
     "#{expression} = #{value}" 
    end.join(', ') 
    $stderr.puts s 
    else 
    stuff.each do 
     |thing| $stderr.print(thing.inspect + "\n") 
    end 
    end 
end 

i = 1 
q i  # => 1 
q {:i} # => i = 1 

name = "Fred" 
q [name, name.length]   # => ["Fred", 4] 
q {[:name, 'name.length']} # => name = "Fred", name.length = 4 

Nota: La función q, y mucho más, ya está disponible en el cute_print joya.

2
foo = 1 
bar = "42" 
baz = Hash.new 

Varspec = Struct.new(:name, :type, :value, :inspect_str) do 
    def to_s 
    "#{name} = (#{type}) #{inspect_str}" 
    end 
end 

lvars = local_variables.map {|lvar| 
    lvar = lvar.to_s 
    val = eval(lvar) 
    val = val.dup rescue val 
    Varspec.new(lvar, val.class, val, val.inspect) 
} 

puts lvars 
# baz = (Hash) {} 
# bar = (String) "42" 
# foo = (Fixnum) 1 

O bien, puede utilizar un depurador. Para eso fueron inventados, después de todo.

Cuestiones relacionadas