I am learning Ruby Singletons and i found some ways to define and get list of Class and Object singleton methods.
Ways to define class singleton methods:
class MyClass
def MyClass.first_sing_method
'first'
end
def self.second_sing_method
'second'
end
class << self
def third_sing_method
'third'
end
end
class << MyClass
def fourth_sing_method
'fourth'
end
end
end
def MyClass.fifth_sing_method
'fifth'
end
MyClass.define_singleton_method(:sixth_sing_method) do
'sixth'
end
Ways to get list of class singletons methods:
#get singleton methods list for class and it's ancestors
MyClass.singleton_methods
#get singleton methods list for current class only
MyClass.methods(false)
Ways to define object singleton methods
class MyClass
end
obj = MyClass.new
class << obj
def first_sing_method
'first'
end
end
def obj.second_sing_method
'second'
end
obj.define_singleton_method(:third_sing_method) do
'third'
end
Way to get list of object singleton methods
#get singleton methods list for object and it's ancestors
obj.singleton_methods
#get singleton methods list for current object only
obj.methods(false)
Are there other ways to do this?
A method given only to a single object is called a singleton method. Singleton methods are often used for elements of a graphic user interface (GUI), where different actions need to be taken when different buttons are pressed. Singleton methods are not unique to ruby, as they appear in CLOS, Dylan, etc.
Singleton is a creational design pattern, which ensures that only one object of its kind exists and provides a single point of access to it for any other code. Singleton has almost the same pros and cons as global variables. Although they're super-handy, they break the modularity of your code.
In case of singleton classes there is no use of static methods as there is only one instance available of the class and every buddy is having the same copy of it.
When you declare a singleton method on an object, Ruby automatically creates a class to hold just that method. This class is called the 'metaclass' of the object. All subsequent singleton methods of this object goes to its metaclass.
First of all, the way to list singleton methods is with singleton_methods
. The methods
method returns a list of the names of public and protected methods of the object. Also, it is defined in the Object
class. Try extend
ing an instance. It is one of the most elegant ways, as it supports code reuse and seems to me very object-oriented:
class Foo
def bar
puts "Hi"
end
end
module Bar
def foo
puts "Bye"
end
end
f = Foo.new
f.bar
#=> hi
f.extend Bar
f.foo
#=> bye
f.methods(false)
#=> []
# the module we extended from is not a superclass
# therefore, this must be empty, as expected
f.singleton_methods
#=> ["foo"]
# this lists the singleton method correctly
g = Foo.new
g.foo
#=> NoMethodError
Edit: In the comment you asked why methods(false)
returns nothing in this case. After reading through the C code it seems that:
methods
returns all the methods available for the object (also the ones in included modules)singleton_methods
returns all the singleton methods for the object (also the ones in included modules) (documentation)singleton_methods(false)
returns all the singleton methods for the object, but not those declared in included modulesmethods(false)
supposedly returns the singleton methods by calling singleton_methods
, but it also passes the parameter false
to it; whether this is a bug or a feature - I do not knowHopefully, this clarifies the issue a little. Bottom line: call singleton_methods
, seems more reliable.
Some more ways:
Class singleton methods
class << MyClass
define_method :sixth_sing_method do
puts "sixth"
end
end
class MyClass
class << self
define_method :fourth_sing_method do
puts "seventh"
end
end
end
Object singleton methods
class << obj
define_method :fourth_sing_method do
puts "fourth"
end
end
Next, you can use define_method
and define_singleton_method
in combination with send
, e.g.
obj.send :define_singleton_method, :nth_sing_method, lambda{ puts "nth" }
and all possible combinations thereof. To use define_method
, you need to capture the singleton class first as in this (the same works for class objects, too)
singleton_class = class << obj; self end
singleton_class.send :define_method, :nth_sing_method, lambda{ puts "nth" }
Another ways is using class_eval
on the singleton class objects:
singleton_class.class_eval do
def nth_sing_method
puts "nth"
end
end
And then you once again may combine send
with class_eval
...
There are myriads of ways, I guess :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With