jnv
jnv

Reputation: 932

Access instance variable using its name (as symbol)

In Ruby, I have this class:


class Position
  attr_reader :x, :y
  def initialize(x, y)
      @x, @y = x, y
  end
end
What I want to do is to access x and y variables using the symbol, something like this:
axis = :x
pos = Position.new(5,6)
 #one way:
pos.axis # 5 (pos.x)
 #other way:
pos.get(axis) # 5 (pos.x)

Thanks to this question I've found with this code, I can achieve the second behavior.

#...
class Position
  def get(var)
    instance_variable_get(("@#{var}").intern)
  end
end
But it seems ugly and inefficient (especially converting symbol to string and back to symbol). Is there a better way?

Upvotes: 6

Views: 6683

Answers (2)

Wes
Wes

Reputation: 6585

Easy, use the send method

class Position
  attr_reader :x, :y

  def initialize(x, y)
    @x, @y = x, y
  end
end
 => nil 

pos = Position.new(5,5)
 => #<Position:0x0000010103d660 @x=5, @y=5> 

axis = :x
 => :x 

pos.send axis
 => 5 

Upvotes: 9

Aaa
Aaa

Reputation: 1854

Here are ways to do both techniques. Assuming we already have your class definition,

position = Position.new(1, 2)
axis = :x
position.send axis #=> 1
axis = :y
position.send axis #=> 2

The Object#send method accepts at least a symbol representing the name of the method to call, and call it. You can also pass arguments to the method after the name and a block, too.

The second way to do this (using your Position#get method) is

class Position
  def get(axis)
    send axis
  end
end

position = Position.new(1, 2)
axis = :x
position.get axis #=> 1
axis = :y
position.get axis #=> 2

I recommend this way because it encapsulates the technique for getting the values. Should you need to change it later, you don't need to change all the code that uses Position.

Upvotes: 3

Related Questions