Singleton methods and class << self
def self.x and class << self
A class method is written with def self.x when there is one of them, and inside class << self when there are several:
class Counter
def self.start
0
end
end
class Clock
class << self
def now
Time.now
end
def today
now.strftime("%Y-%m-%d")
end
end
end
p Counter.start
p Clock.today
ruby -e 'class Counter; def self.start = 0; end; class Clock; class << self; def now = Time.now; def today = now.strftime("%Y-%m-%d"); end; end; p Counter.start; p Clock.today'
0
"2026-11-05"
The second form is the same thing with the receiver self (the class) opened once. It is what a class uses to define a helper that another class method calls, and it is the only way to call private or attr_accessor on class-level state.
Methods on one object
The same mechanism works on a single object, not just on a class. A method defined with the object as the receiver belongs to that object alone:
ruby -e 'o = Object.new; def o.hi = :hi; p o.hi'
:hi
ruby -e 'o = Object.new; def o.hi = :hi; p o.singleton_methods'
[:hi]
singleton_methods lists what was added this way. In application code a per-object method is rare and usually a test double: it replaces one method on one object without touching the class.
Where a class method lives
A class is an object, and its class methods live on its singleton class. A.singleton_class prints as #<Class:A>, and the methods defined there are the ones A.x calls:
ruby -e 'class A; class << self; def x = 1; end; end; p A.singleton_class'
#<Class:A>
ruby -e 'class A; class << self; def x = 1; end; end; p A.singleton_class.instance_methods(false)'
[:x]
That is why private before def self.x does not hide the method from callers, and why private_class_method :x does. The visibility keywords act on the class the method is being defined in, and a class method is one level up.
What to watch for
A class method that needs an instance usually wants to be an instance
method, or a factory that names what it builds:
User.from_row(row). A class full of
self. methods that take the state as arguments is
a module in disguise.
class << self is not a scope for local
variables: a local defined inside it is gone after the
end. Class-level state lives in an instance
variable of the class, @count, not in a local.
Next: Equality and value objects
Article author: Arthur Isaev