Статические локальные переменные для методов в Ruby?

у меня есть это:

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

для тестирования Rspec правильно? Но я хотел бы сделать что-то вроде этого:

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

Я не хочу user_id быть доступным из любого места, кроме этого метода, возможно ли это с Ruby?

5 ответов


этот ответ немного больше по объему, чем ваш вопрос, но я думаю, что он попадает в корень того, что вы пытаетесь сделать, и будет самым простым и наиболее доступным.

Я думаю, что вы действительно ищете здесь заводы. Попробуйте использовать что-то вроде factory_girl, что значительно упростит тестирование.

во-первых, вы настроили бы фабрику для создания любого типа объекта, который вы тестируете, и используете последовательность для электронной почты атрибут:

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

затем, когда вам нужны действительные атрибуты, вы можете использовать

Factory.attributes_for(:model)

вы также можете использовать Factory.create и Factory.build для создания сохраненных и несохраненных экземпляров модели.

есть объяснение гораздо больше возможностей в начало документа, а также инструкции по добавлению фабрик в ваш проект.


это дело о закрытии. Попробуйте это

lambda {
  user_id = 0

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

}.call

обертывание всего в лямбда позволяет переменным, определенным в лямбда, существовать только в области. Можно добавить и другие методы. Удачи!


Вы можете использовать замыкание:

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=>"some_1@thing.com"}
valid_attributes.call  #=>  {:email=>"some_2@thing.com"}

таким образом user_id не будет доступен снаружи.


Я бы использовал переменную экземпляра:

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

единственными переменными Ruby являются локальные переменные, переменные экземпляра, переменные класса и глобальные переменные. Ни один из них не подходит для того, что ты ищешь.

вам, вероятно, нужен синглтон, который хранит user_id и каждый раз дает вам новый идентификационный номер. В противном случае, ваш код не будет потокобезопасным.