2013-03-26 9 views
8

Wie kann ich einen Variablennamen bekommen? ZBRuby: Variablennamen erhalten

def get_var_name(var) 
    # return variable name 
end 

myname = nil 
get_var_name myname #=> myname 

Anfängliche Zweck:

somevar = "value" 

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

Mein Versuch:

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; 
+0

http://stackoverflow.com/questions/1356749 Dies ist näher an Ihre Anforderung. –

Antwort

2

Zuerst können Sie keine puti implementieren und puti a_var aufrufen, um den Ausgang als a_var = value of a_var zu erhalten. Am Rumpf von puti sieht Ruby nur die formalen Parameternamen puti, es kann die tatsächlichen Parameternamen nicht ableiten. In einer anderen Sprache wie C/C++ können Sie Macro verwenden, um Ihre puti zu implementieren. Das ist eine andere Geschichte.

Sie können jedoch put :a_var mit Hilfe von Continuation implementieren. In einer anderen Frage "Can you eval code in the context of a caller in Ruby?", Sony Santos hat eine caller_binding Implementierung bereitgestellt, um die Bindung des Aufrufers (etwas wie die Perl-Aufruferfunktion) zu bekommen.

Die Implementierung sollte etwas geändert werden, da callcc den Rückgabewert des Blocks bei seiner ersten Rückgabe zurückgibt. Sie erhalten also eine Instanz von Continuation anstelle von nil. Hier ist die aktualisierte 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 

Notierte die puti soll nicht die letzte Anweisung des Programms sein, sonst wird das Ruby-Interpreter endet mit sofortiger Wirkung und die Trace-Funktion hat keine Chance zu laufen. Das ist der Punkt der letzten "Platzhalter" -Linie.

+0

Es ist hacky, aber ich mag diesen. Vielen Dank; – ted

8

Sie müssen über die Bindung der aktuellen variablen Umfang tragen, die Sie mit the Binding class tun:

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" 

Die Methode binding() gibt ein Binding-Objekt an, das sich den Kontext an dem Punkt merkt, an dem die Methode aufgerufen wurde. Sie übergeben dann eine Bindung an eval(), und es wertet die Variable in diesem Kontext aus.