Andrew Kim bio photo

Andrew Kim

A Full Stack Web Developer

Twitter Facebook Github Stackoverflow

So we need a way to have programmatic access to our instance variables within a ruby class structure. If you want to learn a little more about ruby classes before learning about getter and setter methods read this

Let’s create a ruby class in a new file we’ll call person.rb:

class Person
  def initialize(name, age, location)
    @name = name
    @age = age
    @location = location
  end
end

bob = Person.new("bob", 25, "DC")
puts bob.name

Great, so we establish a Person class that has the instance variables @name, @age and @location. We also created a new Person object and stored it into the variable bob. So bob has all these great instance variables, but as soon as we run this file we get an error like this one:

$ ruby person.rb
person.rb:10:in `<main>': undefined method `name' for #<Person:0x007ff5c3127760 @name="bob", @age=25, @location="DC"> (NoMethodError)

So, even though we initialize our Person objects with some instance variables we don’t have access to them. Let’s create access to them now through getter methods in person.rb:

class Person
  def initialize(name, age, location)
    @name = name
    @age = age
    @location = location
  end

  # getter methods for name, age and location below
  def name
    @name
  end

  def age
    @age
  end

  def location
    @location
  end
end

bob = Person.new("bob", 25, "DC")
puts bob.name
puts bob.age
puts bob.location
bob.location="NY"
puts bob.location

Awesome, now we have read access to our instance variables @name, @age and @location. But we can’t set or change the instance variables. If we run our program person.rb, we’ll see this error in our terminal:

$ ruby person.rb
bob
25
DC
person.rb:26:in `<main>': undefined method `location=' for #<Person:0x007fcaba08f098 @name="bob", @age=25, @location="DC"> (NoMethodError)

Lets fix this by adding the ability to change or set instance variables. But it doesn’t make sense to be able to change certain attributes. Maybe we’ll have a birthday method that increments age, but we shouldn’t be able to just change your age to whatever you want. You should however be able to change a person’s name or location in case they do change. So let’s add some setter methods for @name and @location. I’ll throw in a celebrate_birthday method as well that will allow us to manipulate the age for kicks. So in our person.rb:

class Person
  def initialize(name, age, location)
    @name = name
    @age = age
    @location = location
  end

  # getter methods for name, age and location below
  def name
    @name
  end

  def age
    @age
  end

  def location
    @location
  end

  # setter methods for name and location below
  def name=(name)
    @name = name
  end

  def location=(location)
    @location = location
  end

  # person has a birthday method
  def celebrate_birthday
    @age += 1
  end
end

bob = Person.new("bob", 25, "DC")
puts bob.name
puts bob.age
puts bob.location
bob.name="bob the second"
bob.location="NY"
bob.celebrate_birthday
puts bob.name
puts bob.age
puts bob.location

So if we run our person.rb file, we should get something like this as output:

$ ruby test.rb
bob
25
DC
bob the second
26
NY

Great! so now we have getter and setter methods for everything we want. It turns out, ruby developers noticed that they were writing this type of code over and over again so they decided to write some helper methods to not have to write out all of this code every time they wanted getter and setter methods. I’m going to comment out the original methods and write the helper methods directly above. Let’s write them now in person.rb:

class Person
  def initialize(name, age, location)
    @name = name
    @age = age
    @location = location
  end

  # getter methods for name, age and location below
  attr_reader :name
  # def name
  #   @name
  # end

  attr_reader :age
  # def age
  #   @age
  # end

  attr_reader :location
  # def location
  #   @location
  # end

  # setter methods for name and location below
  attr_writer :name
  # def name=(name)
  #   @name = name
  # end

  attr_writer :location
  # def location=(location)
  #   @location = location
  # end

  # person has a birthday method
  def celebrate_birthday
    @age += 1
  end
end

bob = Person.new("bob", 25, "DC")
puts bob.name
puts bob.age
puts bob.location
bob.name="bob the second"
bob.location="NY"
bob.celebrate_birthday
puts bob.name
puts bob.age
puts bob.location

If you run person.rb again, you’ll notice the same output. It turns out that often times, instance variables will want both getter and setter methods so there is another helper method attr_accessor So the finalized version of our code in person.rb will look like this:

class Person
  # getter and setter methods for name and location
  attr_accessor :name, :location

  # getter method for age
  attr_reader :age

  # initialize method when new Person object gets instantiated
  def initialize(name, age, location)
    @name = name
    @age = age
    @location = location
  end

  # still need this method for changing age
  def celebrate_birthday
    @age += 1
  end
end

bob = Person.new("bob", 25, "DC")
puts bob.name
puts bob.age
puts bob.location
bob.name="bob the second"
bob.location="NY"
bob.celebrate_birthday
puts bob.name
puts bob.age
puts bob.location

Great! Now we know all about attr_reader, attr_writer, and attr_accessor with respect to getter and setter methods!