2011-08-23 24 views
5

tengo esto:Variables locales estáticas para métodos en Ruby?

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

Para Rspec pruebas de la derecha? Pero me gustaría hacer algo como esto:

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

no quiero user_id para ser accesible desde cualquier lugar, pero ese método, es esto posible con Ruby?

+2

La respuesta corta es no, no existe tal cosa como 'static' en Ruby. ¿Por qué no dejas que la base de datos maneje tu clave de incremento automático? – Emily

+0

Porque es un método para generar atributos válidos para la prueba de Rspec, y algunas cosas deben ser únicas. – Zequez

Respuesta

6

Esta respuesta es un poco más amplia que su pregunta, pero creo que es la raíz de lo que está tratando de hacer, y será la más fácil y más fácil de mantener.

Creo que lo que realmente está buscando aquí son las fábricas. Intente usar algo como factory_girl, lo que hará que muchas pruebas sean mucho más fáciles.

En primer lugar, se había establecido una fábrica para crear cualquier tipo de objeto que se está probando, y el uso de una secuencia para el atributo de correo electrónico:

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 

Entonces, cuando se necesita atributos válidos, puede utilizar

Factory.attributes_for(:model) 

también puede utilizar Factory.create y Factory.build para crear guardados y no guardados casos del modelo.

Hay una explicación de muchas más características en el getting started document, así como instrucciones sobre cómo agregar fábricas a su proyecto.

+0

¡Gracias! ¡Definitivamente verificare esa joya! ^^ – Zequez

0

Las únicas variables que Ruby tiene son variables locales, variables de instancia, variables de clase y variables globales. Ninguno de ellos encaja con lo que buscas.

Lo que probablemente necesite es un singleton que almacene el user_id y le proporcione un nuevo número de identificación cada vez. De lo contrario, su código no será seguro para subprocesos.

4

que haría uso de una variable de instancia:

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

Usted puede utilizar un cierre:

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

De esta manera user_id no será accesible desde el exterior.

7

Este es un estuche de cierre. Prueba este

 
lambda { 
    user_id = 0 

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

}.call 

Envolver todo en lambda permite que existan únicamente las variables definidas dentro de lambda en el ámbito. Puede agregar otros métodos también. ¡Buena suerte!

+0

Probé tu código agregando dos 'p valid_attributes' después de él, pero obtuve' Error NoMethodError: método indefinido '+' para nil: NilClass'. Supongo que 'user_id' dentro de' def' es una variable local inicializada como 'nil'. Tal vez puedas usar el cierre de otra manera. :) –

+0

Hola Sony, me olvidé de def.Lo he cambiado a define_method ya para que ahora pueda acceder a user_id. Otros métodos definidos en lambda de esta manera también pueden compartir la variable user_id. – RubyFanatic

+1

Ok, pero debe usar 'self.class.send: define_method,: valid_attributes', ya que' define_method' es un método de clase privado. De todas formas, prefiero tu solución a la de [mine] (http://stackoverflow.com/questions/7168400/static-local-variables-for-methods-in-ruby/7169076#7169076), porque en mi caso 'valid_attributes' es un proceso (que se debe invocar con 'call' o' [] 'en 1.8.7), y en su caso es un método genuino. –

Cuestiones relacionadas