Struct in Ruby
source link: https://www.tuicool.com/articles/hit/maQfe2v
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Struct in Ruby
In this article, we’re going to explore the following topics:
Struct
The Struct class
A structure is a dummy data container. Unlike an object, it’s used for bundling and serving a set of informations without any logic.
It provides a pair of getter/setter methods for each attribute that it contains. This is similar to the attr_accessor
method for classes.
Feel free to read the Attributes in Ruby
article if you are unfamiliar with the attr_*
methods in Ruby.
The Struct
class is a structure type builder. This class is in charge of defining new structure types that can generate structures afterwards.
Let’s have a look to its ancestor chain
irb> Struct.class
=> Class
irb> Struct.ancestors
=> [Struct, Enumerable, Object, Kernel, BasicObject]
The Struct
class inherits from the default Object
class.
It also includes the Enumerable
module which is in charge of adding a bunch of searching, sorting and traversal methods to a class.
This class shares the exact same ancestor chain as the Array
and Hash
classes.
Feel free to read the Ruby Object Model
article if you are unfamiliar with the Object
class and the ancestor chain.
Feel free to read the The Enumerable module in Ruby: Part I
article if you are unfamiliar with the Enumerable
module.
Structure types and structures
A structure type is a blueprint (class) that contains an immutable list of attributes — also called members .
A structure is the representation in memory of this blueprint (object).
Now let’s see how to create a structure type.
The Struct::new
method is a structure type builder. It allows you to define a new structure type associated to a bunch of defined members passed as parameters
In the first line, we define the Address
structure type which contains the street
, city
and zip
members.
Then we instantiate a structure which is of Address
type that we store in the home
variable.
Each argument of Address.new(‘Broadway’, ‘NYC’, 10002)
matches the corresponding argument of the Struct.new(:street, :city, :zip)
in the given order.
Here, we can see that there is 3 ways to access the value of a member:
-
home.street
: thestreet
accessor method -
home[:city]
: theStruct#[]
with asymbol
key -
home['zip']
: theStruct#[]
with astring
key
Also, notice that if you try to access a non-existing member then a NoMethodError
or a NameError
is raised depending on the way to access this member.
It’s also possible to modify the value of a member for a given structure
Here, we can see that there is 3 ways to modify the value of a member:
-
home.street=
: thestreet=
accessor method -
home[:city]
: theStruct#[]=
with asymbol
key -
home['zip']
: theStruct#[]=
with astring
key
Also notice that if you try to modify a non-existing member then a NoMethodError
or a NameError
is raised depending on the way to modify this member.
Now that we are more familiar with structures and structure types, let’s dig into how structure types are defined behind the scene.
Structure type definition behind the scene
Like any class in Ruby, the Struct::new
method should instantiate an object of type Struct
.
But what if I tell you that the Struct
class is not instantiable ?
irb> Struct.allocate
TypeError (allocator undefined for Struct)
irb> Struct.methods(false)
=> [:new]
In effect, the Struct#allocate
method — in charge of allocating the memory space needed to contain a Struct
object — is undefined at the Struct
class definition.
So, the Struct
class cannot allocate the needed memory to instantiate an object of type Struct
.
Also, the Struct
class overrides the BasicObject#new
method by implementing its own version.
So, how structure types are defined if we cannot instantiate a Struct
?
Behind the scene, Ruby makes a little bit of magic to give the illusion that this class is instantiable.
And all this magic is defined in the Struct#new
method.
If effect, this method doesn’t instantiate a Struct
but, instead, creates a subclass of its own
Here, the Address
constant is actually a Class
that inherits from the Struct
class.
This allows the Address
class to have access to all of the methods and internals of the Struct
class.
So, a structure type is in reality a named class that inherits from the Struct
class and a structure is simply an instance of this named class.
This powerful design allows our structure type to enjoy all the mechanisms that a class provides in Ruby such as class opening, inheritance, mixins etc...
For example, we can re-open the Address
class to add a full_address
method
This is the basic use of the Struct::new
method.
Otherwise, there is another way to use this method
By passing the structure type name as first argument of the Struct::new
, the method automatically defines a new class under the scope of the Struct
class which also inherits from Struct
.
Then we can instantiate the freshly defined Struct::Address
structure type and store the structure in the home
variable.
Voilà !
Thank you for taking the time to read this post :-)
Feel free to :clap: and share this article if it has been useful for you. :rocket:
Here is a link to my last article: Error Handling in Ruby: Part II
.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK