How to create a singleton in ruby?
Personally, 4 ways come to my mind.
The standard library defines a module Singleton
, which produces
Some actions on the class, in particular:
.new
private.instance
that creates and / or returns an instance.#dup
and #clone
to cause an errorI guess this is a classic implementation of a singleton. Anyway, I would write
something like that, be I a java programmer. Nothing special, everything works.
The Module
has a #module_function
method that allows you to use
defined methods "on themselves". This approach is used, for example, inMath
Example:
module M module_function def f :f end end Mf # ==> :f
I would not recommend such a singleton implementation for several reasons:
You can make private methods only with the help of crutches, since module_function
creates a public copy of the method in itself. I came up with just this:
module M module_function def f g end def g 'hello' end singleton_class.send(:private, :g) end Mf # ==> 'hello' Mg # ==> NoMethodError
module_function
in my opinion shouldinclude MyModule
will be used only to make methodsMyModule
. Such a scenarioMath
By the way, you can use extend self
for the same purpose instead ofmodule_function
. This will eliminate the problem of private methods. But let's say
The notorious ruby-style-guide does not approve of this approach (link:
https://github.com/bbatsov/ruby-style-guide#module-function )
I think it's obvious that extend self
works differently, but I'm not sure that there is
some dangerous difference.
upd. still not very obvious. extend self
causes the module to add itself to the list of connected modules (I don’t know how easy it is to write), and module_function
creates copies of the methods. If specifically, look at the code:
module M module_function def f :f end end class A include M end Mf # ==> :f # module_function include A.new.send(:f) # ==> :f module M def f :TROLOLO end end A.new.send(:f) # ==> :TROLOLO Mf # ==> :f
class MyClass def self.f :f end def self.g :g end end MyClass.f # ==> :f
or so:
class MyClass class << self def f :f end private def g :g end end end MyClass.f # ==> :f MyClass.g # ==> NoMethodError
Of course, instead of class
you can use module
. In the above
style guide this approach is not recommended. Instead, recommendmodule_function
.
In my practice, this approach met most often. Personally, he always seemed to me
Some kind of scary crutch, but at the same time I like it more usingSingleton
because MySingleton.do_something
looks more attractive to meMySingleton.instance.do_something
.
Recently, I constantly use this approach:
MySingleton = Object.new class << MySingleton def f g end private def g puts 'hello' end end
Now our singleton is just an Object
instance with the methods we need:
MySingleton.class # ==> Object
Here are the problems here:
#clone
/ #dup
. Solution: redefine them like thisSingleton
#<Object: ...>
. Solution: override the #to_s
and #inspect
. By the wayI think everyone saw the syntax:
class MyClass class << self def do_something_on_class ... end end def do_something_on_instance ... end end
At the same time, I repeatedly noticed that a person does not know what this
design. Actually, in Ruby, objects actually have two classes: one,
whose copy it is, and so on. "singleton class" - singleton class.
Surely you have seen examples where we define methods directly on objects.
Something like this:
x = Object.new def x.hey 'hey' end x.hey # ==> 'hey'
In a class-oriented OOP, an object does not have its own methods. Object behavior
determined by the class to which it belongs. Therefore, we cannot determine
method on an object using def x.hey
, we have to define it in the class. Here is
only if we do this, then all Object
instances will have to
get the #hey
method that we don't want. Therefore Ruby creates an "extra"
object class called singleton class. You can get it using the method#singleton_class
. In general, I got carried away and, probably, only confused those who did not
knew about the "singleton class". This is a very interesting side of Ruby, so I suggest
read about it yourself.
Actually, in short, the construction class << some_object
"enters" into the class
singtona Compare:
class A # enter class A scope def hey 'hey' end end class << A # enter class A singleton class scope def hey 'hello' end end A.new.hey # ==> 'hey' A.hey # ==> 'hello'
Source: https://habr.com/ru/post/340006/
All Articles