2013-03-26 20 views
8

Jak mogę uzyskać nazwę zmiennej? NpRuby: uzyskanie nazwy zmiennej

def get_var_name(var) 
    # return variable name 
end 

myname = nil 
get_var_name myname #=> myname 

początkowe przeznaczenie:

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

http://stackoverflow.com/questions/1356749 To jest bardziej zbliżone do Twoich wymagań. –

Odpowiedz

2

Po pierwsze, nie można wdrożyć puti i bezpośrednio wywołać puti a_var, aby uzyskać dane wyjściowe jako a_var = value of a_var. W ciele puti Ruby widzi tylko formalne nazwy parametrów puti, nie może wywnioskować rzeczywistych nazw parametrów.

W niektórych innych językach, takich jak C/C++, można użyć Macro, aby zaimplementować swoją puti. To inna historia.

Można jednak wdrożyć put :a_var, korzystając z pomocy Continuation. W innym pytaniu "Can you eval code in the context of a caller in Ruby?", Sony Santos wprowadził implementację caller_binding, aby uzyskać powiązanie wywołującego (coś podobnego do funkcji wywołującej perl).

Implementacja powinna zostać nieco zmieniona, ponieważ callcc zwraca zwracaną wartość bloku przy pierwszym powrocie. Dostaniesz więc instancję Continuation zamiast nil. Oto zaktualizowana wersja:

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 

Zanotuj puti nie powinno być ostatnim oświadczenie o swoim programie, inaczej interpreter Ruby natychmiast przerwać, a funkcja śledzenia nie ma szans, aby uruchomić. To jest punkt ostatniej linii "miejsce właściciela".

+0

To jest hacky, ale podoba mi się ten. Dziękuję Ci; – ted

8

Trzeba nosić całej wiązanie bieżącego zakresu zmiennej, co zrobić z 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" 

Metoda binding() podaje obiekt Binding, który zapamiętuje kontekst w momencie wywołania metody. Następnie przekazujesz wiązanie do eval() i ocenia ono zmienną w tym kontekście.

Powiązane problemy