2011-11-04 8 views
12

Próbuję napisać program, który dynamicznie definiuje klasy ruby ​​na podstawie konfiguracji odczytanej z pliku. Wiem, że mogę użyć Class.new, aby to zrobić. Oto przykładowy program:Ruby Dynamic Classes. Jak naprawić "ostrzeżenie: dostęp do zmiennych klasy z poziomu ekranu"

x = [1,2,3] 

Test = Class.new do 
    @@mylist = x 

    def foo 
    puts @@mylist 
    end 
end 

Test.new.foo 

Gdy uruchomię to uzyskać następujące wyjściowe (działa z rubinowym 1.9.3p0):

c:/utils/test.rb:4: warning: class variable access from toplevel 
c:/utils/test.rb:7: warning: class variable access from toplevel 
1 
2 
3

Czy ktoś wie, co powoduje, że te ostrzeżenia i jak mogę pozbyć z nich?

Próbowałem zastępując linię tjhat robi

@@mylist = x

z tym

class_variable_set(:@@mylist, x)

Ale kiedy to zrobić otrzymuję ten błąd Zamiast:

c:/utils/test.rb:7: warning: class variable access from toplevel 
c:/utils/test.rb:7:in `foo': uninitialized class variable @@mylist in Object (NameError) 
     from c:/utils/test.rb:11:in `'

z góry dzięki !

Odpowiedz

7

Wystarczy usunąć to ostrzeżenie, należy użyć class_variable_set metody:

x = [1,2,3] 

Test = Class.new do 
    class_variable_set(:@@mylist, x) 

    def foo 
    puts @@mylist 
    end 
end 
+0

Daje mi to niestety błąd. Zaktualizowałem oryginalne pytanie ze szczegółami. –

+0

Hmm - tylko Ruby 1.9.2 może dać ci takie ostrzeżenie o "dostępie do zmiennych klasy z poziomu ekranu". Ale 'NameError' z komunikatem' uninitialized class variable' może pochodzić tylko z Ruby 1.8, ponieważ metoda 'class_variable_set' jest prywatna w tej wersji. Może to głupie pytanie :) ale czy jesteś pewien, że używasz obu wersji w tej samej wersji ruby? Jeśli używam 1.8 z początkowym fragmentem kodu, nie mam żadnego ostrzeżenia i jeśli używam 1.9 z moim fragmentem, wydaje się, że jest dobrze ... – WarHog

+1

Dziękuję WarHog. Właśnie wypróbowałem twój kod na 1.9.2p290 i działał bez żadnych błędów. Ale kiedy uruchomię go z 1.9.3p0 otrzymuję błąd, który opisałem powyżej. Przyjrzę się temu, co nowego w wersji 1.9.3 i zobaczę, czy coś może wyjaśnić różnicę w zachowaniu. –

2

Zamiast definiowania „mylist” zmienną klasy od klasy podczas deklarowania klasy można deklarować zmienne poziomie klasy na nim później jak poniżej. Pokazano dwie różne metody. Ten pierwszy działa tylko w wersji 1.9, drugi działa w obu wersjach, ale jest mniej idiomatyczny.

x = [1,2,3] 

Test = Class.new do 
    def foo 
    puts @@mylist 
    end 
end 

# ruby 1.9.2 
Test.class_variable_set(:@@mylist, x) 

# ruby 1.8.7 
Test.class_eval { 
    @@mylist = x 
} 

Test.new.foo 
+0

Dzięki za odpowiedź. Niestety, podczas pracy z 1.9.3, pierwsza wersja powoduje błąd, który widziałem, a drugi podaje ostrzeżenia, które miałem! Zaczynam podejrzewać, że jest to zmiana zachowania/regresji w rubinie 1.9.3. –

15

To nie robi tego, co myślisz, że robi. Ponieważ nie tworzysz klasy ze słowem kluczowym class, zmienna klasy jest ustawiana na Object, a nie Test. Implikacje tego są dość ogromne, dlatego właśnie ostrzega cię Ruby. Zmienne klas są współużytkowane przez przodków, a obiekty zazwyczaj dziedziczą po Object.

Powiązane problemy