开发者

Static local variables for methods in Ruby?

开发者 https://www.devze.com 2023-03-30 11:40 出处:网络
I have this: def valid_attributes { :email => \"some_#{rand(9999)}@thing.com\" } end For R开发者_Python百科spec testing right? But I would like to do something like this:

I have this:

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

For R开发者_Python百科spec 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消