6

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?
Community
  • 1
  • 1
jnv
  • 882
  • 10
  • 18

2 Answers2

9

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 
Wes
  • 6,455
  • 3
  • 22
  • 26
  • 1
    There is no need to convert `axis` to string. `axis` is a Symbol, and in `.send`, the method name must be passed as a Symbol. => `pos.send(axis)` – karatedog Mar 29 '11 at 22:48
  • 2
    This doesn't actually access the instance variable, it just calls the accessor. – David Moles May 21 '15 at 21:35
3

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.

Aaa
  • 1,854
  • 12
  • 18