In the following article, we’re going to explore the following topics:
- the
alias
keyword - the
alias_method
method - aliases and scopes
- aliases behind the scene
Ruby provides an alias
keyword to deal with method and attribute aliases
Here we define a User#fullname
method and we define a username
alias for this method.
Then, the username
alias is aliased with a name
alias.
So, a call to name
or username
will call the code defined within the User#fullname
method and return the same result.
Note that it’s possible to define an alias for an existing alias.
The Module#alias_method
method shares the same behavior as the alias
keyword but it complies to the method syntax
Like the alias
keyword, we define a User#fullname
method and we define a username
alias for this method.
Then the username
alias is aliased with a name
alias.
So, a call to name
, username
or fullname
returns the same result.
We can see that the alias_method
method takes a String
or a Symbol
as argument that allows Ruby to identify the alias and the method to alias.
If alias
and Module#alias_method
share the same behavior, then what’s the purpose of dealing with two things that do the exact same job?
The answer is that they don’t exactly do the same thing.
In effect, the Module#alias_method
acts differently than the alias
keyword on one specific point: the scope.
Let’s have a look to this example
Here we can see that the call to alias_method
within the Device#alias_description
method defines the describe
alias on the Microwave#description
method and not on the Device#description
one.
Now let’s see what happens with the alias
keyword
Here we can see that the call to alias
within the Device#alias_description
method sets the describe
alias on the Device#description
method and not on the Microwave#description
one.
Let’s get back to the User
class example to figure out what happens when an alias is defined
Behind the scene the username
alias is treated as a method.
In effect, in Ruby each method is inserted in a table that keeps track of all the methods of your program. This table is called the method_entry
table.
So, for the fullname
method, a new entry is inserted in the method_entry
table. This entry contains the following informations:
- the
:fullname
method identifier - the content of the
User#fullname
method - the
User
class
Now, let’s have a look to the new entry for the username
alias. This entry contains:
- the
:username
method identifier - The content of the
User#fullname
method - the
User
class
That’s how the alias
keyword and the alias_method
method are able to define an alias for an existing method.
Note that an entry contains a way more informations than what I’ve described. But let’s keep it simple to focus on aliases.
Voilà!
In this article, we’re going to explore the following topics:
- inheritance and the
instance
method clone
anddup
methods
Have a look to the Part I (3-minutes read) before to read this article.
In the previous article we’ve seen that after including the Singleton
module, an instance
method is implicitly defined within the including class
Here, the Singleton
module defines the Ebook.instance
method when it’s included in the Ebook
class.
Cool! But what happens if a RubyObjectModel
class inherits from the Ebook
class ?
In the above example, the RubyObjectModel
class inherits from the Ebook
class.
As the Ebook
class includes the Singleton
module, then a RubyObjectModel.instance
class method is implicitly defined.
So, the RubyObjectModel
class defines its own version of the instance
method and doesn’t use the one defined in the Ebook
class.
This freshly defined method returns a uniq RubyObjectModel
instance — and not an Ebook
instance.
This mechanism allows the RubyObjectModel
class to inherit from the behaviors of the Singleton
module and the Ebook
class while dealing with an independent RubyObjectModel
instance.
So the inheritance principle is not broken, while the singleton pattern is persisted through inheritance.
Ok, this is cool! But when inheriting from a class that includes the Singleton
module can be useful?
Here, we define a base class named Client
that encapsulate a bunch of common attributes as url
, port
and credentials
.
After, we define the DBClient
and ApiClient
classes that derivate from the Client
class.
As only one instance of these classes is required to coordinate actions across the program, then making them inheriting from the Client
class seems to be a good decision.
In effect, with this pattern the DBClient
and the ApiClient
:
- include the
Singleton
module - encapsulate common attributes
- define common methods
When the Singleton
module is included in a class then the Object#clone
and Object#dup
methods are overridden by the Singleton
ones
In effect, these methods are redefined to raise an error.
This is due to the fact that, by essence, a uniq instance of a class shouldn’t be duplicable.
Feel free to read theRuby Object Model
article if you are unfamiliar with theObject
class.
Otherwise, the Singleton
module provides a clone
class method that instantiate a new anonymous class.
Voilà !