2012-03-12 20 views
5

Próbuję ustawić zmienną lokalną do istniejącego wiązaniaWstrzykiwanie zmiennej lokalnej do wiązania

def foo_callback 
    lambda { |name| p name } 
end 
b = foo_callback.binding 

Wiązanie nie ma żadnych zmiennych lokalnych na początek:

b.eval("local_variables") # => [] 

Let nam ustawić prymitywny zmiennej lokalnej do wiązania:

b.eval("age=30") 

wszystko działa zgodnie z oczekiwaniami:

b.eval("local_variables") # => ["age"] 
b.eval("age") # => 30 

Teraz spróbujmy ustawić zakaz prymitywny zmiennej lokalnej do wiązania:

country = Country.first 
b.eval("lambda {|v| country = v}").call(country) 

Uwaga:technique ustawiania zmienna jest zapożyczona z facet gem. Próbowałem Ruby 1.9 bezpieczne implementation z takimi samymi wynikami.

Wiązanie nie odzwierciedla lokalnej zmiennej country.

b.eval("local_variables") # => ["age"] 

Jak obejść ten problem? Zasadniczo chcę zadeklarować nową zmienną w powiązaniu przy użyciu wartości istniejącej, nieprostowej zmiennej.

Jestem na Ruby 1.8.7.

+0

wiązania() jest prywatny, więc wiązanie nigdy można nazwać tak: 'b = foo_callback.binding' – 7stud

+0

@ 7stud Można. Uruchom kod w konsoli ruby ​​'def foo_callback lambda {| name | p nazwa} koniec b = foo_callback.binding' –

Odpowiedz

5

Tworzysz country poza oprawą, a następnie country wewnątrz lambda jest ważny tylko w tym zakresie. Dlaczego nie chcesz wstrzyknąć tego również do wiązania?

Aktualizacja

Spróbuj deklarując zmienną poza zakresem lambda ale wewnątrz zakresu wiązania:

b.eval("country = nil; lambda {|v| country = v}").call(country) 
+0

'eval' przyjmuje ciąg jako parametr, więc nie mogę przekazać wartości istniejącej zmiennej przez odniesienie. Kod, którego używam, jest bardzo podobny do tego, którego użyto w gemie "facet": https://github.com/rubyworks/facets/blob/master/lib/core/facets/binding/op_get.rb –

+0

Uwaga na temat * aspekty nie działające w wersji 1.9 nie są zachęcające. Wiązania są bardzo ważne w Ruby, ale zawsze odkryłem, że istnieje tylko bardzo źle przemyślany system do manipulowania nimi i używania ich. Zaktualizowałem swoją odpowiedź szorstkim ukłuciem w rozwiązanie. – tadman

+0

Mam takie same wyniki, gdy użyłem bezpiecznego wykonania ruby ​​1.9: https://github.com/rubyworks/facets/blob/master/lib/core/facets/binding/with.rb#L7 –

2

Problem polega na tym, że podczas tworzenia nowego lambda, w obrębie innej lambda, a to tworzy nowy zakres.

Aby być bardziej zrozumiałym, powiązanie "b" będzie miało w swoim zakresie wszystkie zmienne lokalne dostępne w zakresie funkcji #foo_callback oraz wszystkie zmienne lokalne dostępne w pierwszym lambda. Druga lambda, którą utworzyłeś, jest nowym zakresem, a zatem nowe zmienne lokalne utworzone w tym zakresie nie są zachowywane poza zakresem, chyba że zostaną zainicjowane spoza zakresu wewnętrznego.

Dlatego wiele osób zainicjuje zmienne lokalne jako zerowe przed wprowadzeniem bloku. Można również zrobić to, co robi to samo: zmienne

country = country 
{...block that sets country to something non-nil...} 
return country 

instancji nie mają tego zakresu problemu i są dostępne przez wewnętrznych i zewnętrznych zakresów funkcją jest.

Ex:

b.eval("lambda {|c| @country = c}").call(country) 
b.eval "instance_variables" 

powinno działać.

I ktoś pokazał mi odpowiedź, podczas gdy pisałem ten :)

Powiązane problemy