Introduction
A singleton method is a method defined on a specific object rather than on its class. Only that one object has the method โ no other instances of the same class do. This is one of Ruby’s most distinctive features and the foundation of how class methods work.
Defining Singleton Methods
Direct Definition
obj = Object.new
def obj.talk
"Hi from singleton method!"
end
obj.talk # => "Hi from singleton method!"
Object.new.talk # => NoMethodError โ other objects don't have it
Using instance_eval
instance_eval changes self to the receiver, allowing you to define singleton methods inside a block:
s1 = "hello"
s2 = "world"
s1.instance_eval do
def shout
upcase + "!!!"
end
end
s1.shout # => "HELLO!!!"
s2.shout # => NoMethodError โ s2 doesn't have this method
Using define_singleton_method
dog = Object.new
name = "Rex"
dog.define_singleton_method(:speak) do
"#{name} says: Woof!"
end
dog.speak # => "Rex says: Woof!"
Class Methods Are Singleton Methods
Here’s the key insight: class methods are singleton methods defined on the class object.
Since every class in Ruby is an object (an instance of Class), you can define singleton methods on it โ and those become class methods:
class People
# This is a singleton method on the People class object
def self.kind
"human"
end
end
# Equivalent ways to define the same method:
def People.kind
"human"
end
People.singleton_class.define_method(:kind) { "human" }
All three define the same singleton method on the People class object.
Class Methods Are Inherited
Singleton methods on classes are inherited by subclasses:
class People
def self.kind
"human"
end
end
class Student < People
end
puts People.kind # => "human"
puts Student.kind # => "human" (inherited!)
This works because Ruby’s method lookup for class methods walks the singleton class hierarchy, which mirrors the regular class hierarchy.
The Singleton Class
Every Ruby object has a hidden singleton class (also called eigenclass or metaclass) that stores its singleton methods. You can open it with class << obj:
obj = Object.new
class << obj
def greet
"Hello from singleton class!"
end
def farewell
"Goodbye!"
end
end
obj.greet # => "Hello from singleton class!"
obj.farewell # => "Goodbye!"
For a class, class << self opens the class’s singleton class โ this is where class methods live:
class Config
class << self
def default_timeout
30
end
def default_retries
3
end
attr_accessor :debug_mode
end
end
Config.default_timeout # => 30
Config.debug_mode = true
puts Config.debug_mode # => true
Inspecting Singleton Methods
class Dog
def self.species
"Canis lupus familiaris"
end
end
rex = Dog.new
def rex.fetch(item)
"#{item} fetched!"
end
# Singleton methods on an instance
puts rex.singleton_methods.inspect
# => [:fetch]
# Singleton methods on a class (= class methods)
puts Dog.singleton_methods(false).inspect
# => [:species]
# Check if an object has a singleton class
puts rex.singleton_class
# => #<Class:#<Dog:0x...>>
puts Dog.singleton_class
# => #<Class:Dog>
Every Object Has Two Classes
Every Ruby object belongs to two classes:
- Its regular class โ shared with all instances
- Its singleton class โ unique to that object
dog = Dog.new
# Regular class (shared)
dog.class # => Dog
dog.is_a?(Dog) # => true
# Singleton class (unique to this object)
dog.singleton_class # => #<Class:#<Dog:0x...>>
# Method lookup order
dog.singleton_class.ancestors
# => [#<Class:#<Dog:0x...>>, Dog, Object, Kernel, BasicObject]
When you call a method on dog, Ruby first looks in dog’s singleton class, then in Dog, then up the ancestor chain.
Practical Use Cases
Per-Object Behavior
class Logger
def log(msg)
puts "[DEFAULT] #{msg}"
end
end
production_logger = Logger.new
staging_logger = Logger.new
# Override log behavior only for production
production_logger.define_singleton_method(:log) do |msg|
puts "[PROD #{Time.now}] #{msg}"
# also send to external service
end
production_logger.log("Server started") # => [PROD 2026-03-30 ...] Server started
staging_logger.log("Server started") # => [DEFAULT] Server started
Mocking in Tests
Singleton methods are commonly used in tests to mock specific objects:
# In a test
payment_gateway = PaymentGateway.new
# Override just this instance's charge method
def payment_gateway.charge(amount)
{ success: true, transaction_id: "test-123" }
end
result = payment_gateway.charge(100)
puts result[:success] # => true
DSL Configuration Objects
class AppConfig
def self.configure
config = new
yield config
config
end
def method_missing(name, *args)
if name.to_s.end_with?('=')
define_singleton_method(name.to_s.chomp('=')) { args.first }
else
super
end
end
end
config = AppConfig.configure do |c|
c.database_url = "postgres://localhost/myapp"
c.redis_url = "redis://localhost:6379"
c.debug = true
end
puts config.database_url # => "postgres://localhost/myapp"
puts config.debug # => true
Singleton Class Hierarchy
The singleton class hierarchy mirrors the regular class hierarchy:
Regular classes: Student < People < Object
Singleton classes: #<Class:Student> < #<Class:People> < #<Class:Object>
This is why class methods are inherited โ Student’s singleton class inherits from People’s singleton class.
class People
def self.kind; "human"; end
end
class Student < People; end
# Student's singleton class inherits from People's singleton class
puts Student.singleton_class.superclass
# => #<Class:People>
puts Student.singleton_class.ancestors.inspect
# => [#<Class:Student>, #<Class:People>, #<Class:Object>, ...]
Summary
| Concept | Description |
|---|---|
| Singleton method | Method defined on a specific object, not its class |
| Singleton class | Hidden class that stores an object’s singleton methods |
| Class method | Singleton method on a class object |
class << obj |
Opens the singleton class of obj |
class << self |
Opens the current class’s singleton class (inside a class body) |
obj.singleton_methods |
Lists singleton methods on obj |
obj.singleton_class |
Returns the singleton class of obj |
Resources
- Ruby Docs: Object#singleton_class
- Ruby Docs: Object#define_singleton_method
- Metaprogramming Ruby โ Paolo Perrotta
- Ruby Under a Microscope โ Pat Shaughnessy
Comments