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