Ruby Singleton Class
Syntax[edit | edit source]
- singleton_class = class << object; self end
Remarks[edit | edit source]
Singleton classes only have one instance: their corresponding object. This can be verified by querying Ruby's
instances = ObjectSpace.each_object object.singleton_class instances.count # => 1 instances.include? object # => true
<, they can also be verified to be subclasses of the object's actual class:
object.singleton_class < object.class # => true
Singleton classes[edit | edit source]
All objects are instances of a class. However, that is not the whole truth. In Ruby, every object also has a somewhat hidden singleton class.
This is what allows methods to be defined on individual objects. The singleton class sits between the object itself and its actual class, so all methods defined on it are available for that object, and that object only.
object = Object.new def object.exclusive_method 'Only this object will respond to this method' end object.exclusive_method # => "Only this object will respond to this method" Object.new.exclusive_method rescue $! # => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>
The example above could have been written using
object.define_singleton_method :exclusive_method do "The method is actually defined in the object's singleton class" end
Which is the same as defining the method on
# send is used because define_method is private object.singleton_class.send :define_method, :exclusive_method do "Now we're defining an instance method directly on the singleton class" end
Before the existence of
singleton_class as part of Ruby's core API, singleton classes were known as metaclasses and could be accessed via the following idiom:
class << object self # refers to object's singleton_class end
Inheritance of Singleton Class[edit | edit source]
Subclassing also Subclasses Singleton Class[edit | edit source]
class Example end Example.singleton_class #=> #<Class:Example> def Example.foo :example end class SubExample < Example end SubExample.foo #=> :example SubExample.singleton_class.superclass #=> #<Class:Example>
Extending or Including a Module does not Extend Singleton Class[edit | edit source]
module ExampleModule end def ExampleModule.foo :foo end class Example extend ExampleModule include ExampleModule end Example.foo #=> NoMethodError: undefined method
Accessing Singleton Class[edit | edit source]
There are two ways to get singleton class of an object
- Reopening singleton class of an object and returning
singleton_class = class << object self end
Accessing Instance/Class Variables in Singleton Classes[edit | edit source]
Singleton classes share their instance/class variables with their object.
class Example @@foo = :example end def Example.foo class_variable_get :@@foo end Example.foo #=> :example
class Example def initialize @foo = 1 end def foo @foo end end e = Example.new e.instance_eval <<-BLOCK def self.increase_foo @foo += 1 end BLOCK e.increase_foo e.foo #=> 2
Blocks close around their instance/class variables target. Accessing instance or class variables using a block in
instance_eval isn't possible. Passing a string to
class_eval or using
class_variable_get works around the problem.
class Foo @@foo = :foo end class Example @@foo = :example Foo.define_singleton_method :foo do @@foo end end Foo.foo #=> :example
Message Propagation with Singleton Class[edit | edit source]
Instances never contain a method they only carry data. However we can define a singleton class for any object including an instance of a class.
When a message is passed to an object (method is called) Ruby first checks if a singleton class is defined for that object and if it can reply to that message otherwise Ruby checks instance's class' ancestors chain and walks up on that.
class Example def foo :example end end Example.new.foo #=> :example module PrependedModule def foo :prepend end end class Example prepend PrependedModule end Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject] e = Example.new e.foo #=> :prepended def e.foo :singleton end e.foo #=> :singleton
Reopening (monkey patching) Singleton Classes[edit | edit source]
There are three ways to reopen a Singleton Class
class_evalon a singleton class.
defto define a method on the object's singleton class directly
class Example end Example.singleton_class.class_eval do def foo :foo end end Example.foo #=> :foo
class Example end class << Example def bar :bar end end Example.bar #=> :bar
class Example end def Example.baz :baz end Example.baz #=> :baz
Every object has a singleton class which you can access
class Example end ex1 = Example.new def ex1.foobar :foobar end ex1.foobar #=> :foobar ex2 = Example.new ex2.foobar #=> NoMethodError
Introduction[edit | edit source]
Ruby has three types of objects:
- Classes and modules which are instances of class Class or class Module.
- Instances of classes.
- Singleton Classes.
Each object has a class which contains its methods:
class Example end object = Example.new object.class # => Example Example.class # => Class Class.class # => Class
Objects themselves can't contain methods, only their class can. But with singleton classes, it is possible to add methods to any object including other singleton classes.
def object.foo :foo end object.foo #=> :foo
foo is defined on singleton class of
Example instances can not reply to
Ruby creates singleton classes on demand. Accessing them or adding methods to them forces Ruby to create them.