The Ruby Koans: About Class Methods
The Ruby Koans are a fantastic resource to introducing the concepts and syntax of the Ruby programming language. In this post, we’ll explore the concepts posed by about_class_methods.rb: class methods, instance methods, and singleton methods.
Objects, Classes, and Class Objects
Let's start with some fundamental truths:
Instances of a class are objects.
A class itself is an instance of
Class.Since classes are objects, they can have their own methods.
Objects are instances of a class
class Dog
end
fido = Dog.new
puts fido.is_a?(Object) # => true
Every object in Ruby inherits from Object, so even instances of Dog are objects.
Classes are objects too
puts Dog.is_a?(Class) # => true
puts Dog.is_a?(Object) # => true
Since Dog itself is an instance of Class, it is both a class and an object at the same time.
Instance Methods vs. Class Methods
Instance methods are methods that belong to a specific instance of a class and operate on that instance’s data, whereas class methods belong to the class itself and can be called without creating an instance.
Defining an Instance Method
class Dog
def wag
:instance_level_wag
end
end
fido = Dog.new
puts fido.wag # => :instance_level_wag
Here, wag is an instance method. Each instance of Dog (e.g., fido) can call this method.
Defining a Class Method
There are multiple ways to define class methods:
Using self.method_name
class Dog
def self.class_method
:dogs_class_method
end
end
puts Dog.class_method # => :dogs_class_method
By using self. inside the class definition, we define a class method directly on Dog.
Using class << self (Singleton Class Syntax)
class Dog
class << self
def another_class_method
:still_another_way
end
end
end
puts Dog.another_class_method # => :still_another_way
This technique defines class methods using the singleton class, which is a special, hidden class that Ruby creates for each object to hold methods specific to that object. A singleton class (also called a metaclass or eigenclass) is unique to each object and allows defining methods that only that particular object can access. In this case, class << self opens up the singleton class of Dog, allowing us to define methods that belong only to the Dog class itself.
For example:
class Dog
class << self
def bark
'Woof!'
end
end
end
puts Dog.bark # => 'Woof!'
This is equivalent to:
class Dog
def self.bark
'Woof!'
end
end
puts Dog.bark # => 'Woof!'
Singleton methods can also be applied to individual instances:
fido = Dog.new
def fido.speak
'Arf!'
end
puts fido.speak # => 'Arf!'
However, this method is only available to fido, not other instances of Dog.
Singleton Methods on Objects
Since everything in Ruby is an object, we can define methods on individual instances:
fido = Dog.new
def fido.wag
:fidos_wag
end
puts fido.wag # => :fidos_wag
However, this method only applies to fido, not other Dog instances:
rover = Dog.new
puts rover.wag # => NoMethodError
Class Instance Variables vs. Instance Variables
Instance variables inside a class belong to instances of that class, whereas instance variables inside the class definition itself belong to the class object.
class Dog
attr_accessor :name
end
def Dog.name
@name
end
fido = Dog.new
fido.name = "Fido"
puts fido.name # => "Fido"
puts Dog.name # => nil
The instance variable @name on fido does not affect Dog because Dog.name refers to an instance variable on the class object, not on an instance.
The Value of self in a Class Definition
Inside a class definition, self refers to the class itself:
class Dog
puts self # => Dog
end
Since self refers to the class, we can define class methods like this:
class Dog
def self.class_method2
:another_way_to_write_class_methods
end
end
puts Dog.class_method2 # => :another_way_to_write_class_methods
Returning Values from Class Definitions
In Ruby, the last expression inside a class definition determines its return value:
LastExpression = class Dog
21
end
puts LastExpression # => 21
For example, this behavior can be used in metaprogramming to dynamically define constants or class-level settings based on computations performed within the class definition:
DefaultLimit = class Configuration
100 * 2
end
puts DefaultLimit # => 200
Here, the last evaluated expression (100 * 2) is returned and assigned to DefaultLimit.
Calling Class Methods from Instances
Although class methods belong to the class, instances can still access them indirectly:
fido = Dog.new
puts fido.class.another_class_method # => :still_another_way
This works because fido.class evaluates to Dog, and Dog.another_class_method is a valid class method.
Which Class Method Syntax Should You Use?
Both of the following approaches work for defining class methods:
class Demo
def self.method_one
end
class << self
def method_two
end
end
end
Which one should you prefer?
self.method_nameis more common and easier to read. This is usually what you should do.class << selfis useful when defining multiple class methods at once.
Hopefully this post has clarified some key concepts in this chapter of the Koans. As you continue your Ruby journey, may you keep in mind (my personal favorite axiom from the test output): mountains are merely mountains.