Ruby: imprime el nombre de la variable y luego su valor

Cuál es la mejor manera de escribir una función (o algo DSLish) que me permita escribir este código en Ruby. ¿Cómo construiría la función write_pair?

username = "tyndall" write_pair username # where write_pair username outputs username: tyndall 

Es posible de hacer? Buscando la manera más simple de hacer esto.

Claro que es posible!

Mi solución prueba la var por Object # object_id identity: http://codepad.org/V7TXRxmL
Está lisiado en el estilo de paso vinculante …
A pesar de que funciona solo para los vars locales aún, se puede hacer fácilmente como “universal”, agregando el uso de los otros métodos scope-variable-listing como instance_variables etc.

 # the function must be defined in such a place # ... so as to "catch" the binding of the vars ... cheesy # otherwise we're kinda stuck with the extra param on the caller @_binding = binding def write_pair(p, b = @_binding) eval(" local_variables.each do |v| if eval(v.to_s + \".object_id\") == " + p.object_id.to_s + " puts v.to_s + ': ' + \"" + p.to_s + "\" end end " , b) end # if the binding is an issue just do here: # write_pair = lambda { |p| write_pair(p, binding) } # just some test vars to make sure it works username1 = "tyndall" username = "tyndall" username3 = "tyndall" # the result: write_pair(username) # username: tyndall 

Si es posible usar un símbolo en lugar del nombre de la variable, podría hacer algo como esto:

 def wp (s, &b) puts "#{s} = #{eval(s.to_s, b.binding)}" end 

En uso:

 irb(main):001:0> def wp (s, &b) irb(main):002:1> puts "#{s} = #{eval(s.to_s, b.binding)}" irb(main):003:1> end => nil irb(main):004:0> var = 3 => 3 irb(main):005:0> wp(:var) {} var = 3 

Tenga en cuenta que debe pasar el bloque vacío {} al método o no puede obtener el enlace para evaluar el símbolo.

Hice una macro vim para esto:

 " Inspect the variable on the current line (in Ruby) autocmd FileType ruby nmap ,i ^"oy$Iputs "A: #{("opA).inspect}" 

Coloque la variable que le gustaría inspeccionar en una línea por sí mismo, luego escriba ,i (coma entonces i) en modo normal. Resulta esto:

 foo 

dentro de esto:

 puts "foo: #{(foo).inspect}" 

Esto es bueno porque no tiene dependencias externas (por ejemplo, no es necesario tener una biblioteca cargada para usarla).

Basándose en las respuestas anteriores relacionadas con símbolos y enlaces … si le conviene pasar el nombre de la variable como un símbolo (¿a quién no le gusta cortar las teclas extra?), Intente esto:

 def wp(var_name_as_sym) # gets caller binding, which contains caller's execution environment parent_binding = RubyVM::DebugInspector.open{|i| i.frame_binding(2) } # now puts the symbol as string + the symbol executed as a variable in the caller's binding puts %Q~#{var_name_as_sym.to_s} = #{eval("#{var_name_as_sym.to_s}.inspect", parent_binding)}~ end aa=1 bb='some bb string' os = OpenStruct.new(z:26, y:25) 

Salida de la consola:

 > wp :aa aa = 1 => nil > wp :bb bb = "some bb string" => nil > wp :os os = # => nil 

Usando ruby ​​2.2.2p95

(Crédito a baranding para obtener el enlace del contexto de llamada)

En realidad, no se puede obtener el nombre de una variable en Ruby. Pero podrías hacer algo como esto:

data = {"username" => "tyndall"}

O incluso,

 username = "tyndall" data = {"username", "password", "favorite_color"} data.each { |param| value = eval(param) puts "#{param}: #{value}" } 

Esta es una solución simple:

  def bug string puts string + eval(string) end 

Esto es más legible:

  def bug string puts '#' * 100 puts string + ': ' + eval(string).inspect end 

Se invoca así:

 bug "variable" 

Si necesita llevar la variable real con usted, debe escribirla dos veces, pero luego puede hacerlo en línea. Así:

 puts "variable: #{variable}" 
 def write_pair var, binding puts "#{ var } = #{ eval(var, binding)}" end username = "tyndall" write_pair "username", binding 

Esto parece extraño porque el enlace nunca se define, pero funciona. De Ruby: obteniendo nombre de variable :

El método binding () proporciona un objeto Binding que recuerda el contexto en el punto donde se llamó el método. Luego pasa un enlace a eval () y evalúa la variable en ese contexto.

Asegúrese de pasar una cadena, no la variable.

 # make use of dynamic scoping via methods and instance vars @_binding = binding def eval_debug(expr, binding = @_binding) "#{expr} => #{eval(expr, binding)}" end # sample invocation: x = 10 puts eval_debug "x" puts eval_debug "x**x"