2011-08-23 15 views
5

ho questo:Variabili locali statiche per i metodi in Ruby?

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

Per Rspec test giusto? Ma mi piacerebbe fare qualcosa di simile:

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

Non voglio user_id per essere accessibile da qualsiasi luogo, ma quel metodo, è questo possibile con Ruby?

+2

La risposta breve è no, non esiste qualcosa come 'static' in Ruby. Perché non lasciare che il database gestisca la chiave di auto-incremento? – Emily

+0

Perché è un metodo per generare attributi validi per il test di Rspec e alcune cose devono essere uniche. – Zequez

risposta

6

Questa risposta ha una portata leggermente più ampia della tua domanda, ma penso che diventi la base di ciò che stai cercando di fare, e sarà la più semplice e la più gestibile.

Penso che quello che cerchi davvero sia fabbriche. Prova a utilizzare qualcosa come factory_girl, che renderà molti test molto più semplici.

In primo luogo, si sarebbe creato una fabbrica per creare qualsiasi tipo di oggetto è si sta testando, e utilizzare una sequenza per l'attributo e-mail:

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 

Poi, quando hai bisogno di attributi validi, è possibile utilizzare

Factory.attributes_for(:model) 

È inoltre possibile utilizzare Factory.create e Factory.build per creare salvati e non salvati istanze del modello.

C'è una spiegazione di molte più funzioni nello getting started document, nonché le istruzioni su come aggiungere fabbriche al progetto.

+0

Grazie! Controllerò definitivamente quella gemma! ^^ – Zequez

0

Le uniche variabili Ruby sono variabili locali, variabili di istanza, variabili di classe e variabili globali. Nessuno di loro si adatta a quello che stai cercando.

Quello che probabilmente è necessario è un singleton che memorizza il id_utente e ti dà un nuovo numero ID ogni volta. Altrimenti, il tuo codice non sarà thread-safe.

4

userei una variabile di istanza:

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

È possibile utilizzare una chiusura:

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]"} 

In questo modo user_id non saranno accessibili dall'esterno.

7

Questo è un caso di chiusura. Prova questo

 
lambda { 
    user_id = 0 

    self.class.send(:define_method, :valid_attributes) do 
    user_id += 1 
    { :email => "some_#{user_id}@thing.com" } 
    end 

}.call 

Il wrapping di tutto in lambda consente alle variabili definite all'interno di lambda di esistere solo nell'ambito. Puoi anche aggiungere altri metodi. In bocca al lupo!

+0

Ho provato il tuo codice aggiungendo due 'p valid_attributes' dopo di esso, ma ho ottenuto' Errore NoMethodError: metodo non definito '+' per nil: NilClass'. Immagino che 'user_id' all'interno di' def' sia una variabile locale inizializzata come 'nil'. Forse puoi usare la chiusura in un altro modo. :) –

+0

Ciao Sony, mi sono dimenticato di def.L'ho modificato in define_method, quindi ora dovrebbe essere in grado di accedere a user_id. Altri metodi definiti all'interno di lambda in questo modo possono anche condividere la variabile user_id. – RubyFanatic

+1

Ok, ma devi usare 'self.class.send: define_method,: valid_attributes', poiché' define_method' è un metodo di classe privata. Ad ogni modo, preferisco la tua soluzione su [mine] (http://stackoverflow.com/questions/7168400/static-local-variables-for-methods-in-ruby/7169076#7169076), perché nel mio caso 'valid_attributes' è un proc (che deve essere chiamato con 'call' o' [] 'in 1.8.7), e nel tuo caso è un metodo genuino. –

Problemi correlati