Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 215
Zequez Avatar asked Aug 23 '11 22:08

Zequez


3 Answers

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!

like image 177
RubyFanatic Avatar answered Nov 15 '22 07:11

RubyFanatic


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.

like image 34
Emily Avatar answered Nov 15 '22 08:11

Emily


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=>"[email protected]"}
valid_attributes.call  #=>  {:email=>"[email protected]"}

This way user_id won't be accessible outside.

like image 43
Sony Santos Avatar answered Nov 15 '22 07:11

Sony Santos