2011-08-23 27 views
5

mam to:Statyczne zmienne lokalne dla metod w Ruby?

def valid_attributes 
    { :email => "some_#{rand(9999)}@thing.com" } 
end 

Dla rspec testowania prawo? Ale chciałbym zrobić coś takiego:

def valid_attributes 
    static user_id = 0 
    user_id += 1 
    { :email => "some_#{user_id}@thing.com" } 
end 

nie chcę user_id być dostępne z dowolnego miejsca, ale to metoda, jest to możliwe z Ruby?

+2

Krótka odpowiedź brzmi: nie, nie ma czegoś takiego jak "static" w Ruby. Dlaczego nie pozwolić, aby baza danych obsługiwała twój automatyczny klucz inkrementacyjny? – Emily

+0

Ponieważ jest to metoda generowania poprawnych atrybutów do testowania Rspec, a niektóre rzeczy muszą być unikatowe. – Zequez

Odpowiedz

6

Ta odpowiedź jest nieco szersza niż pytanie, ale wydaje mi się, że jest ona podstawą tego, co próbujesz zrobić, i będzie najłatwiejsza i najłatwiejsza w utrzymaniu.

Myślę, że to, czego naprawdę szukasz, to fabryki. Spróbuj użyć czegoś takiego, jak factory_girl, co znacznie ułatwi testowanie.

pierwsze, można by założyć fabrykę tworzyć niezależnie od typu obiektu to Ty testujesz i użyć sekwencję atrybutu email:

FactoryGirl.define do 
    factory :model do 
    sequence(:email) {|n| "person#{n}@example.com" } 
    # include whatever else is required to make your model valid 
    end 
end 

Wtedy, kiedy trzeba ważnych atrybutów, można użyć

Factory.attributes_for(:model) 

można również użyć Factory.create i Factory.build aby utworzyć zapisane i niezapisane instancji modelu.

Wyjaśnienie wielu funkcji dostępnych w getting started document, a także instrukcji dotyczących dodawania fabryk do projektu.

+0

Dzięki! Zdecydowanie sprawdzę ten klejnot! ^^ – Zequez

0

Jedyne zmienne, które Ruby ma, to zmienne lokalne, zmienne instancji, zmienne klasy i zmienne globalne. Żadne z nich nie pasuje do tego, o co prosisz.

Najprawdopodobniej jest to singleton, który przechowuje identyfikator użytkownika, i za każdym razem podaje nowy numer identyfikacyjny. W przeciwnym razie twój kod nie będzie bezpieczny dla wątków.

4

użyję instancję zmiennej:

def valid_attributes 
    @user_id ||= 0 
    @user_id += 1 
    { :email => "some_#{@user_id}@thing.com" } 
end 
4

Można użyć Zamknięcie:

def validator_factory 
    user_id = 0 
    lambda do 
    user_id += 1 
    { :email => "some_#{user_id}@thing.com" } 
    end 
end 

valid_attributes = validator_factory 

valid_attributes.call #=> {:email=>"[email protected]"} 
valid_attributes.call #=> {:email=>"[email protected]"} 

ten sposób user_id nie będą dostępne na zewnątrz.

7

To jest zamknięcie. Wypróbuj to, co jest w lambda, aby zmienne zdefiniowane w ramach lambda istniały tylko w zakresie. Możesz także dodać inne metody. Powodzenia!

+0

Próbowałem twojego kodu, dodając po nim dwa 'p valid_attributes', ale dostałem' Error NoMethodError: undefined method '+' dla nil: NilClass'. Domyślam się, że 'user_id' wewnątrz' def' jest lokalną zmienną zainicjowaną jako 'nil'. Może możesz użyć zamknięcia w inny sposób. :) –

+0

Cześć Sony, zapomniałem o def.Zmieniłem go już na define_method, więc teraz powinien mieć dostęp do id_użytkownika. Inne metody zdefiniowane w ramach lambda w ten sposób mogą również współdzielić zmienną user_id. – RubyFanatic

+1

Ok, ale musisz użyć 'self.class.send: define_method,: valid_attributes', ponieważ' define_method' jest prywatną metodą klasy. W każdym razie wolę twoje rozwiązanie od [moje] (http://stackoverflow.com/questions/7168400/static-local-variables-for-methods-in-ruby/7169076#7169076), ponieważ w moim przypadku "valid_attributes" to proc (który musi być wywołany z 'call' lub' [] 'w 1.8.7), aw twoim przypadku jest to prawdziwa metoda. –