Object-oriented programming reduces the complexity of large programming software thus making the software easier to maintain. In a pure object-oriented language, everything inside an Object. The goal of OOPs is to combine the data and functions which are operating those data so that the data cannot be accessed by any other part of the code.

Ruby is a pure Object oriented language and everything is considered as an object. Primitve types Strings, Numbers, true or false are also an Object. 

OOP's concepts

Class

Class is nothing but a blueprint of a data type. It simply defines, what an instance of the class consists and possible functions which can be performed on the object of the class. In Ruby, even classes are objects of "class" class

A class definition starts with the keyword class followed by the class name and is delimited with an end. For example, we defined the Box class using the keyword class as follows

class Table
   code
end

 

The name must begin with a capital letter and by convention names that contain more than one word are run together with each word capitalized and no separating characters (CamelCase).

Define Ruby Objects

A class provides the blueprints for objects, so basically an object is created from a class. We declare objects of a class using new keyword. Following statements declare two objects of class Table

tab1 = Table.new
tab2 = Table.new

 

The initialize Method

The initialize method is a standard Ruby class method and works almost same way as constructor works in other object oriented programming languages. The initialize method is useful when we want to initialize some class variables at the time of object creation. This method may take a list of parameters and like any other ruby method it would be preceded by def keyword as shown below

class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

 

The instance variables are kind of class attributes and they become properties of objects once objects are created using the class. Every object's attributes are assigned individually and share no value with other objects. They are accessed using the @ operator within the class but to access them outside of the class we use public methods, which are called accessor methods. If we take the above defined class Table then @width and @height are instance variables for the class Table

class Table
   def initialize(w,h)
      # assign instance variables
      @width, @height = w, h
   end
end

 

The accessor & setter Methods

To make the variables available from outside the class, they must be defined within accessor methods, these accessor methods are also known as a getter methods. Following example shows the usage of accessor methods

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# create an object
table= Table.new(10, 20)

# use accessor methods
x = table.printWidth()
y = table.printHeight()

puts "Width of the table is : #{x}"
puts "Height of the table is : #{y}"

 

Output

 
Width of the table is : 10
Height of the table is : 20

 

Similar to accessor methods, which are used to access the value of the variables, Ruby provides a way to set the values of those variables from outside of the class using setter methods, which are defined as below

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
table= Table.new(10, 20)

# use setter methods
table.setWidth = 30
table.setHeight = 50

# use accessor methods
x = table.getWidth()
y = table.getHeight()

puts "Width of the table is : #{x}"
puts "Height of the table is : #{y}"

 

Output

Width of the table is : 30
Height of the table is : 50

 

The instance Methods

The instance methods are also defined in the same way as we define any other method using def keyword and they can be used using a class instance only as shown below. Their functionality is not limited to access the instance variables, but also they can do a lot more as per our requirement

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
table= Table.new(10, 20)

# call instance methods
a = table.getArea()
puts "Area of the tableis : #{a}"

 

Output

Area of the table is : 200

 

The class Methods and Variables

The class variables is a variable, which is shared between all instances of a class. In other words, there is one instance of the variable and it is accessed by object instances. Class variables are prefixed with two @ characters (@@). A class variable must be initialized within the class definition as shown below.

A class method is defined using def self.methodname(), which ends with end delimiter and would be called using the class name as classname.methodname

#!/usr/bin/ruby -w

class Table
   # Initialize our class variables
   @@count = 0
   def initialize(w,h)
      # assign instance avriables
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Table count is : #@@count"
   end
end

# create two object
table1= Table.new(10, 20)
table2= Table.new(30, 100)

# call class method to print table count
Table.printCount()

output

Table count is : 2

The to_s Method

Any class we define should have a to_s instance method to return a string representation of the object. Following is a simple example to represent a Table object in terms of width and height

#!/usr/bin/ruby -w

class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # define to_s method
   def to_s
      "(w:#@width,h:#@height)"  # string formatting of the object.
   end
end

# create an object
table= Table.new(10, 20)

# to_s method will be called in reference of string automatically.
puts "String representation of table is : #{box}"

output

String representation of table is : (w:10,h:20)

Access Control

Ruby gives us  three levels of protection at instance methods level, which may be public, private, or protected. Ruby does not apply any access control over instance and class variables.

  • Public Methods − Public methods can be called by anyone. Methods are public by default except for initialize, which is always private.

  • Private Methods − Private methods cannot be accessed, or even viewed from outside the class. Only the class methods can access private members.

  • Protected Methods − A protected method can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.

Following is a simple example to show the syntax of all the three access modifiers

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method by default it is public
   def getArea
      getWidth() * getHeight
   end

   # define private accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # instance method to print area
   def printArea
      @area = getWidth() * getHeight
      puts "Big Table area is : #@area"
   end
   # make it protected
   protected :printArea
end

# create an object
table= Table.new(10, 20)

# call instance methods
a = table.getArea()
puts "Area of the table is : #{a}"

# try to call protected or methods
table.printArea()

 

Output

Area of the table is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)

 

Class Inheritance

One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to create and maintain an application.

Inheritance also provides an opportunity to reuse the code functionality and fast implementation time but unfortunately Ruby does not support multiple levels of inheritances but Ruby supports mixins. A mixin is like a specialized implementation of multiple inheritance in which only the interface portion is inherited.

When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class or superclass, and the new class is referred to as the derived class or sub-class.

Ruby also supports the concept of subclassing, i.e., inheritance and following example explains the concept. The syntax for extending a class is simple. Just add a < character and the name of the superclass to our class statement. For example, following define a class BigTable as a subclass of Table

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigTable < Table

   # add a new instance method
   def printArea
      @area = @width * @height
      puts "Table box area is : #@area"
   end
end

# create an object
table= BigTable.new(10, 20)

# print the area
table.printArea()

output

Big table  area is : 200

Methods Overriding

Though we can add new functionality in a derived class, but sometimes we would like to change the behavior of already defined method in a parent class. We can do so simply by keeping the method name same and overriding the functionality of the method

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigTable < Table

   # change existing getArea method as follows
   def getArea
      @area = @width * @height
      puts "Big table area is : #@area"
   end
end

# create an object
table= BigTable.new(10, 20)

# print the area using overriden method.
table.getArea()

Operator Overloading

We'd like the + operator to perform vector addition of two Table objects using +, the * operator to multiply a Table width and height by a scalar, and the unary - operator to do negate the width and height of the Table

class Table
   def initialize(w,h)     # Initialize the width and height
      @width,@height = w, h
   end

   def +(other)       # Define + to do vector addition
      Table.new(@width + other.width, @height + other.height)
   end

   def -@           # Define unary minus to negate width and height
      Table.new(-@width, -@height)
   end

   def *(scalar)           # To perform scalar multiplication
      Table.new(@width*scalar, @height*scalar)
   end
end

Freezing Objects

Sometimes, we want to prevent an object from being changed. The freeze method in Object allows us to do this, effectively turning an object into a constant. Any object can be frozen by invoking Object.freeze. A frozen object may not be modified: we can't change its instance variables.

We can check if a given object is already frozen or not using Object.frozen? method, which returns true in case the object is frozen otherwise a false value is return

#!/usr/bin/ruby -w

# define a class
class Table
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
table= Table.new(10, 20)

# let us freez this object
table.freeze
if( table.frozen? )
   puts "Table object is frozen object"
else
   puts "Table object is normal object"
end

# now try using setter methods
table.setWidth = 30
table.setHeight = 50

# use accessor methods
x = table.getWidth()
y = table.getHeight()

puts "Width of the table is : #{x}"
puts "Height of the table is : #{y}"

 

Output

Table object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
   from test.rb:39

Class Constants

We can define a constant inside a class by assigning a direct numeric or string value to a variable, which is defined without using either @ or @@. By convention, we keep constant names in upper case.

Once a constant is defined, we cannot change its value but we can access a constant directly inside a class much like a variable but if we want to access a constant outside of the class then we would have to use classname::constant

#!/usr/bin/ruby -w

# define a class
class Table
   TABLE_COMPANY = "TATA Inc"
   TABLEWEIGHT = 10
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
table= Table.new(10, 20)

# call instance methods
a = table.getArea()
puts "Area of the table is : #{a}"
puts Table::TABLE_COMPANY
puts "Table weight is: #{Table::TABLEWEIGHT}"

Output

Area of the table is : 200
TATA Inc
Table weight is: 10

Create Object Using Allocate

There may be a situation when we want to create an object without calling its constructor initialize i.e. using new method, in such case we can call allocate, which will create an uninitialized object

#!/usr/bin/ruby -w

# define a class
class Table
   attr_accessor :width, :height

   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method
   def getArea
      @width * @height
   end
end

# create an object using new
table1 = Table.new(10, 20)

# create another object using allocate
table2 = Table.allocate

# call instance method using table1
a = table1.getArea()
puts "Area of the table is : #{a}"

# call instance method using table2
a = table2.getArea()
puts "Area of the table is : #{a}"

 

Output

Area of the table is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in `getArea': undefined method `*' 
   for nil:NilClass (NoMethodError) from test.rb:29

 

Subscribe For Daily Updates