Methods are great for DRYing up your code and organizing logic in a single place. They act a little bit like a black box. Here are some tidbits that might not be so obvious with Ruby methods.

All methods have to be called on an object

In Ruby, there has to be an object that receives a method call, even if you don’t see it. For example, the “puts” method or the multiplication operator:

puts "Hello"
puts self
puts self.class
p self.class.ancestors
# Hello
# main
# Object
# [Object, Kernel, BasicObject]

puts 8.class
p 8.class.ancestors
# Integer
# [Integer, Numeric, Comparable, Object, Kernel, BasicObject]

# * is actually a method with the 2 being passed in as the parameter
puts 8.*(2)
puts 8 * 2

# 16
# 16

So in words:

  • “puts” is a method
  • This method is called on an object.
  • That object is stored in the self variable.
  • That variable points to the object which is named main (Akin to how a string variable points to a an object named String).

Obviously you won’t be able to call “self.puts” because Ruby doesn’t allow explicit receivers for private methods. I won’t get into the details of self but just know that its value could change depending on where you are in your program and is the default receiver for method calls.

Fun fact: Within a method, Ruby will check whether something is a local variable first. If not, it looks for an implicit receiver next.

So we call methods on objects and sometimes we’ll pass a block and/or a method parameter. It’s good to keep in mind Ruby passes variables by reference. For instance:

def say_something(words)
  words[5] = "z"

my_word = "hello"

# The method call actually altered the value
puts my_word
# helloz

Default parameters

def add_headphone(brand, model, version=1.0)
  puts brand
  puts model
  puts version

add_headphone("HiFiMan", "HE-1000")
add_headphone("HiFiMan", "HE-1000", 2.0)