Skip to content
AgileLogics
5 min read

Instance Methods, self, and to_s

Prerequisites: Accessors

Inside an instance method, self refers to the object the method was called on. Most of the time you don't need to write it — Ruby assumes it — but it's there when you need it.

class Temperature
  attr_reader :celsius

  def initialize(celsius)
    @celsius = celsius
  end

  def fahrenheit
    celsius * 9.0 / 5 + 32   # same as self.celsius
  end

  def hotter_than?(other)
    celsius > other.celsius
  end

  def to_s
    "#{celsius}°C"
  end
end

today = Temperature.new(24)
yesterday = Temperature.new(19)

puts today.fahrenheit
puts today.hotter_than?(yesterday)
puts today
puts "Today it's #{today}"
p today.celsius
75.2
true
24°C
Today it's 24°C
24
  • celsius inside fahrenheit calls the reader on the current object (self).
  • hotter_than?(other) compares this object with another one of the same class.
  • Defining to_s controls how the object looks when printed with puts or placed in interpolation. Without it, Ruby prints something like #<Temperature:0x000... @celsius=24>.

inspect is to_s's developer-facing sibling — it's what p and irb show. Ruby's default inspect lists the instance variables, which is usually fine.

Method chaining with self

Returning self from a method lets callers chain calls:

class Order
  attr_reader :items

  def initialize
    @items = []
  end

  def add(item)
    @items << item
    self
  end
end

order = Order.new.add("tea").add("cake")
p order.items
["tea", "cake"]

Common mistakes

  • Overriding to_s to return something other than a string. puts then shows the default object description instead.

Practice

Give the Temperature class a to_s that shows both scales, like 24°C / 75.2°F.

Show solution
class Temperature
  attr_reader :celsius

  def initialize(celsius)
    @celsius = celsius
  end

  def fahrenheit = celsius * 9.0 / 5 + 32

  def to_s = "#{celsius}°C / #{fahrenheit}°F"
end

puts Temperature.new(24)