简体   繁体   中英

Static local variables for methods in Ruby?

I have this:

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

For Rspec testing right? But I would like to do something like this:

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

I don't want user_id to be accessible from anywhere but that method, is this possible with Ruby?

This is a closure case. Try this

lambda {
  user_id = 0

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

}.call

Wrapping everything in lambda allows the variables defined within lambda to only exist in the scope. You can add other methods also. Good luck!

This answer is a little larger in scope than your question, but I think it gets at the root of what you're trying to do, and will be the easiest and most maintainable.

I think what you're really looking for here is factories. Try using something like factory_girl , which will make a lot of testing much easier.

First, you'd set up a factory to create whatever type of object it is you're testing, and use a sequence for the email attribute:

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

Then, when you need valid attributes, you can use

Factory.attributes_for(:model)

You can also use Factory.create and Factory.build to create saved and unsaved instances of the model.

There's explanation of a lot more of the features in the getting started document , as well as instructions on how to add factories to your project.

You can use a closure:

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

This way user_id won't be accessible outside.

I'd use an instance variable:

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

The only variables Ruby has are local variables, instance variables, class variables and global variables. None of them fit what you're after.

What you probably need is a singleton that stores the user_id, and gives you a new ID number each time. Otherwise, your code won't be thread-safe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM