Martin
Martin

Reputation: 305

How to use dynamic variables many times in ruby

So I am trying to create dynamic variables, and then use them again later without having to type out the full name. The test code I made is as follows

players = [1, 2, 3, 4]

players.each |player|
  instance_variable_set("@player_#{player}_hand", "foo")
  instance_variable_set("@player_#{player}_value", "bar")
}

puts @player_1_hand # => foo
puts @player_3_value # => bar

players.each { |player| 
puts "@player_#{player}_hand" 
}

# => @player_1_hand
# => @player_2_hand
# => @player_3_hand
# => @player_4_hand

I want to call and/or update these variables dynamically but I don't know how to do that after I initialize them. The documentation I have found has been more confusing than helpful. Can someone explain how to use these correctly?

Upvotes: 1

Views: 113

Answers (4)

Tom
Tom

Reputation: 432

When a you want an attr_accessor for every property, a Struct instead of a class will make them for you automatically.

Player = Struct.new(:number, :hand, :value)

players = Array.new

(1..4).each do |i|
  player = Player.new(i)
  player.hand = 'something'
  player.value = 'blah'
  players.push player
end

players.each do |player|
  puts "Player #{player.number} has hand #{player.hand} with value #{player.value}"
end

Output:

Player 1 has hand something with value blah
Player 2 has hand something with value blah
Player 3 has hand something with value blah
Player 4 has hand something with value blah

Upvotes: 1

anothermh
anothermh

Reputation: 10536

I want to warn you that the answer I'm going to give you will work for what you are trying to accomplish, but the way you're going about it is akin to using a wrench when you need a hammer. Sure, the wrench might work, but I'd fire any plumber that didn't use the right tools.

players.each { |p| puts instance_variable_get("@player_#{p}_hand") }

More about instance_variable_get can be found at apidock.

In general though, you should stay away from instance variables unless you are creating instances of a class. But for a script like this, stick with normal variables and stay away from instance variables.

Upvotes: 2

cmramseyer
cmramseyer

Reputation: 447

I recommend that you follow OOP concepts creating a Player object instead of many instance variables, one for each attribute. So, instead of

@player_1_hand
@player_3_value

Try with a Player class

class Player
  attr_accessor :number, :hand, :value
  def initialize(number)
    @number = number
  end
end

And then

p1 = Player.new(1)
p2 = Player.new(2)
p3 = Player.new(3)
p4 = Player.new(4)
[p1,p2,p3,p4].each do |player|
  player.hand = ...
  player.value = ...
end


p1.hand #=> ...
p1.value #=> ...

Upvotes: 8

developer_hatch
developer_hatch

Reputation: 16224

players = [1, 2, 3, 4]

players.each { |player|
instance_variable_set("@player_#{player}_hand", "foo")
instance_variable_set("@player_#{player}_value", "bar")
}

To call your variables use eval

players.each { |player| 
puts instance_variable_get("@player_#{player}_hand") 
puts instance_variable_get("@player_#{player}_value")
}

To update your variables use instance_variable_set again

players.each { |player| 
instance_variable_set("@player_#{player}_hand", instance_variable_get("@player_#{player}_hand") + (player + 5).to_s)
puts instance_variable_get("@player_#{player}_hand")
}

all that prints:

foo
bar
foo
bar
foo
bar
foo
bar
foo6
foo7
foo8
foo9

Upvotes: 2

Related Questions