2013-03-26 36 views
8

Come posso ottenere un nome di variabile? Ad esempio,Ruby: nome variabile della variabile

def get_var_name(var) 
    # return variable name 
end 

myname = nil 
get_var_name myname #=> myname 

scopo iniziale:

somevar = "value" 

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

La mia prova:

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 Questo è più vicino alle vostre esigenze. –

risposta

2

In primo luogo, non è possibile implementare uno puti e chiamare direttamente puti a_var per ottenere l'output come a_var = value of a_var. Nel corpo di puti, Ruby vede solo i nomi dei parametri formali di puti, non può dedurre i nomi dei parametri effettivi.

In un altro linguaggio come C/C++, è possibile utilizzare Macro per implementare il proprio puti. Questa è un'altra storia.

Tuttavia, è possibile implementare put :a_var, con l'aiuto di Continuation. In un'altra domanda "Can you eval code in the context of a caller in Ruby?", Sony Santos ha fornito un'implementazione caller_binding per ottenere l'associazione del chiamante (qualcosa come la funzione perl chiamante).

L'implementazione deve essere modificata un po ', perché callcc restituisce il valore di ritorno del blocco al suo primo ritorno. Quindi otterrai un'istanza di Continuation anziché nil. Ecco la versione aggiornata:

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 

Annotare il puti non dovrebbe essere l'ultima istruzione del programma, altrimenti l'interprete ruby ​​terminerà immediatamente e la funzione di traccia non ha alcuna possibilità di correre. Questo è il punto dell'ultima linea "segnaposto".

+0

È hacky ma mi piace questo. Grazie; – ted

8

È necessario trasportare attraverso il legame della corrente portata variabile, che si fa con 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" 

Il metodo binding() fornisce un oggetto Binding che ricorda il contesto nel punto in cui è stato chiamato il metodo. Quindi si passa un'associazione in eval() e si valuta la variabile in tale contesto.