Multiton
Multiton is an implementation of the multiton pattern in pure Ruby. Some its features include:
- Can be used to implement the singleton pattern in a very straightforwad way.
- Transparent interface that makes designing multiton classes as easy as designing regular ones.
- Support for serializing and deserializing multiton instances.
- Clonning, duplicating and inheriting from a multiton class will create a new multiton class.
- Thread safety, implemented via shared/exclusive locks.
- Compatible with MRI, JRuby and other Ruby implementations.
Installation
Add this line to your application's Gemfile:
gem "ruby_multiton"
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruby_multiton
Usage
Implementing a singleton class
The easiest use case for Multiton is to implement a singleton class. To achieve this Multiton mimics the approach used by the Singleton module from Ruby's standard library:
require "multiton"
class C
extend Multiton
end
C.instance.object_id #=> 47143710911900
C.instance.object_id #=> 47143710911900
As an example lets create a singleton object that returns the amount of seconds elapsed since it was first initialized:
class Timestamp
extend Multiton
def initialize
self.initialized_at = Time.now
end
def elapsed_seconds
Time.now - initialized_at
end
private
attr_accessor :initialized_at
end
Timestamp.instance #=> #<Timestamp:0x00562e486384c8 @initialized_at=2017-04-17 20:00:15 +0000>
# Some time later...
Timestamp.instance.elapsed_seconds #=> 542.955918039
Implementing a multiton class
To implement a multiton class we will need a key
to be able to access the different instances afterwards. Multiton
achieves this by using the parameters passed to the initialize
method as the key
:
require "multiton"
class C
extend Multiton
def initialize(key)
end
end
C.instance(:one).object_id #=> 47387777147320
C.instance(:one).object_id #=> 47387777147320
C.instance(:two).object_id #=> 47387776632880
C.instance(:two).object_id #=> 47387776632880
As an example lets create multiton objects representing playing cards that we can check if they were drawn or not:
class Card
extend Multiton
def initialize(number, suit)
self.has_been_drawn = false
end
def draw
self.has_been_drawn = true
end
def drawn?
has_been_drawn
end
private
attr_accessor :has_been_drawn
end
Card.instance(10, :spades).drawn? #=> false
Card.instance(5, :hearts).draw
Card.instance(10, :spades).draw
Card.instance(5, :hearts).drawn? #=> true
Card.instance(10, :spades).drawn? #=> true
Card.instance(2, :diamonds).drawn? #=> false
Serializing and deserializing multiton instances
Multiton instances can be serialized and deserialized like regular objects. Continuing with the previous Card
example:
Card.instance(2, :diamonds).drawn? #=> false
serialized_card = Marshal.dump(Card.instance(2, :diamonds))
Marshal.load(serialized_card).drawn? #=> false
Card.instance(2, :diamonds).draw
Marshal.load(serialized_card).drawn? #=> true
Clonning, duplicating and inheriting from multiton classes
Multiton supports cloning, duplicating and inheriting from a multiton class:
require "multiton"
class C
extend Multiton
end
D = C.clone
E = D.dup
class F < E
end
F.instance.object_id #=> 47418482076880
F.instance.object_id #=> 47418482076880
Note that C
, D
, E
and F
are all considered different classes and will consequently not share any instances.
Contributing
- Fork it ( https://github.com/gdeoliveira/ruby_multiton/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am "Add some feature"
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request