From what I’ve understood Object-Oriented programming is very popular and it has lots of advantages. The programmer may have a closer feeling of working with real-life entities due to the multitask nature of the objects in OOP. From my point of view OOP is a good way to keep all your code organise. Each object contains its data and functionality within its scope and if its methods are written in an abstract way they can be reused for other objects or for a different project.
I am still working in the OO Ruby section and it is taking me some time to understand all the concepts and why or when to use them. Here it is what I have learned so far:
Creating a class
Class names begin with capital letters because they are stored in Ruby constants. If our class name contains two words, the name should be CamelCased.
1 2 3 |
class Dog end |
Instantiation
Every time we want to represent a new individual in our program we should instantiate an object of that type (Dog.new). We call these individuals instances.
1 2 3 4 5 6 |
class Dog end flecha = Dog.new flecha #=> #<Dog:0x007fc52c2d7d20> #This is the object identifier, Ruby Object Notation. |
Instances variables
An instance variable represents a singular property of an individual, of an instance. This variable is accessible in any instance method in a particular instance of a class. The name of the instance variable is written with a @ at the beginning of the word: @instance_variable_name.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Dog def name=(name) #This is the instance variable @name = name end def name @name end end flecha = Dog.new #We create an instance of Dog flecha.name = "flecha" #We set the name of this new instance to "flecha" |
Instance methods
We call the methods defined within the object’s class instance methods because they are methods that belong to any instance of the class.
They provide a mechanism for an object to expose to the outside world its data. They can manipulate the internal state of an object and provide some functionality for an individual object too.
1 2 3 4 5 6 7 8 9 10 11 |
class Dog # Class body # Instance Method Definition def bark puts "Woof!" end end flecha = Dog.new flecha.bark #> "Woof!" #Now flecha can bark |
Attribute readers, writers and accesors
Our object’s instances can have attributes, like a name or hair colour in the case of our Dog class. In order to set these attributes we have to use a writer and in order to have these data available in the outside world we have to have a reader. It is very important to use an instance variable (@name), otherwise the getter method couldn’t read the data that we set in the writer method because it is out of scope.
1 2 3 4 5 6 7 8 9 10 |
class Dog def name=(name)#This is the setter or writer method @name = name end def name #This is the getter or reader method @name end end |
This is the explicit method for the attribute @name. There is another faster way to do it using a macro: the attr_writer, the attr_reader and the attr_accessor that does the work of the two previous macros. In Ruby a macro is like a method that instead of returning a Ruby datatype returns more Ruby code. The implementation of macros is considered metaprogramming.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Dog attr_writer :name #This is the setter method attr_reader :name #This is the getter method end #This snippet is equal to the following one: class Dog attr_accessor :name end |
When to use attr_accessor vs a custom reader/writer.
The attr_accessor macro will provide a naive interface for reading and writing to an instance variable. Anytime we need something conceptually different or more complex, we should build our own reader or writer.
Self
Whenever an object needs to refer to itself, the keyword “self” is used.
In an instance method, self will always refer to the instance itself and in a class method, self will always refer to the class itself.
Class variable
Class variables are for properties that belong to the entire class. A class level variable can be used for example for instance memoization, for keeping track of all instances of a class or for collaborating data. The name of the class variable is written with a double @ at the beginning of the word: @@class_variable_name.
1 2 3 4 5 6 7 8 |
class Dog attr_accessor :name @@all = [] #This is a class variable def self.all @@all end end |
#self.all is a class method for reading data stored in the class variable @@all. This is a class reader, very similar to an instance reader method that reads an instance property.
Class methods
With these methods we can access any class variable. A class method operate on the entire class and expose the class’ scope to the rest of our program. They don’t have access to the instance scope.
1 2 3 |
def self.class_method_name # some code end |
The most common class methods are:
Class finders
A class finder method returns existing instances.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Dog attr_accessor :name @@all = [] def initialize(name) @name = name self.class.all << self # self in the initialize method is our new instance # self.class is Dog # self.class.all == Dog.all end def self.all @@all end def self.find_by_name(name) #This is the class finder self.all.find{|dog| dog.name == name} end end |
Custom class constructors
A class constructor is any class method that instantiates an instance of the class.
1 2 3 4 5 6 7 |
class Dog @@all = [] def self.create @@all << self.new end end |
Class operators
A class operator is perfect to manipulate any class level data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Dog attr_accessor :name @@all = [] def self.all @@all end def initialize(name) @name = name @@all << self end def self.destroy_all self.all.clear end end |