-2

I have a class called Team. I am trying to create many instances of it and call them team1, team2, etc. I am trying something like

for x in (1..20)
  instancename="team#{x}"
  instancename=Team.new
end

I am getting the memory address of the string like "Team:0x007f949b01d3f8". I assume I have to use instance_variable_set, but I'm having a hard time figuring out the syntax.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
user809334
  • 45
  • 3
  • 7
    Normally this smell indicates you should be using an Array or a Hash. `@instances = {}; (1..20).each { |i| @instances[i] = Team.new }` – Gareth Aug 25 '13 at 23:13
  • 1
    first google hit: http://apidock.com/ruby/Object/instance_variable_set – Karoly Horvath Aug 25 '13 at 23:17
  • I know, that's how I came up with the idea of using it, but I can't grok how to do it, hence the downvoted question. Gareth's solution does work, but then I have an array of instances, rather than just having the instances by themselves. – user809334 Aug 25 '13 at 23:24
  • 4
    This seems like an X/Y problem. What do you plan to *do* with the instances? Why do you need to pre-generate named instances instead of working with a collection object? – Todd A. Jacobs Aug 25 '13 at 23:25

1 Answers1

2

TL;DR

You can do what you want with Kernel#eval or Object#instance_variable_set. You can also generate collections directly. If your needs are much more complex, then you may want to think about alternative data structures.

Using Eval

You are partly on the right track in that you need to define the variables in the current scope. While there are a number of ways to do this, the following will work:

Team = Struct.new :foo
for x in (1..20) do
  eval "\@team#{x} = Team.new"
end

This creates your instance variables:

@team20
#=> #<struct Team foo=nil>

using interpolation.

Interpolation Without Eval

There are alternatives to Kernel#eval, of course, like Object#instance_variable_set. Consider this example:

Team = Struct.new :foo
(1..20).each { |i| instance_variable_set "@team#{i}", Team.new }

I can't really see how it makes much difference in your particular case, but this allows you to avoid #eval while still doing interpolation of the variable name.

Use a Collection

Since I can't imagine how you would use this as anything other than a collection anyway, you might as well just create a collection in the first place. For example:

Team = Struct.new :team_id
teams = (1..20).map { |i| Team.new i }
teams[9]
#=> #<struct Team team_id=10>

You can even find teams in your collection by some value, if you prefer. For example:

teams.select { |t| t.team_id == 10 }
#=> [#<struct Team team_id=10>]

None of this requires a unique variable name. You can use array position or object attributes instead, if you really need to distinguish them.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199