Object-oriented programming concepts in Ruby

Ruby is a powerful and popular programming language known for its simplicity and productivity. One of the main reasons behind Ruby's success is its strong support for object-oriented programming (OOP) concepts. In this article, we will explore some of the important OOP concepts in Ruby and how they can be used to write clean and modular code.

Classes and Objects

In Ruby, everything is an object, including numbers, strings, and even classes themselves. At the heart of OOP in Ruby are classes and objects. A class can be thought of as a blueprint or a template for creating objects. It defines the attributes (data) and behaviors (methods) that objects of that class will have.

For example, let's say we want to create a Person class. We would define it as follows:

class Person
  # attributes
  attr_accessor :name, :age

  # constructor
  def initialize(name, age)
    @name = name
    @age = age
  end

  # methods
  def greet
    puts "Hello, my name is #{@name} and I am #{@age} years old."
  end
end

Now, we can create objects (instances) of the Person class and manipulate them:

person1 = Person.new("John", 25)
person1.greet
# Output: Hello, my name is John and I am 25 years old.

person2 = Person.new("Alice", 30)
person2.greet
# Output: Hello, my name is Alice and I am 30 years old.

Inheritance

Inheritance is another important OOP concept supported by Ruby. It allows us to create a new class (called a subclass) based on an existing class (called a superclass), inheriting its attributes and methods. This promotes code reuse and allows us to build more specialized classes.

Let's extend our Person class to include a Student subclass:

class Student < Person
  # additional attribute
  attr_accessor :student_id

  def initialize(name, age, student_id)
    super(name, age)
    @student_id = student_id
  end

  def study
    puts "#{@name} is studying."
  end
end

Now, we can create Student objects and use both the inherited and specific methods:

student1 = Student.new("Bob", 22, "S1234")
student1.greet
# Output: Hello, my name is Bob and I am 22 years old.

student1.study
# Output: Bob is studying.

Encapsulation

Encapsulation is the practice of hiding the internal details of an object and exposing only what is necessary. In Ruby, encapsulation is achieved through access modifiers. The three access modifiers are public, protected, and private.

  • public methods can be called from anywhere.
  • protected methods can only be called within the defining class and its subclasses.
  • private methods can only be called within the defining class.
class BankAccount
  attr_reader :balance

  def initialize(initial_balance)
    @balance = initial_balance
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    validate_withdrawal(amount)
    @balance -= amount
  end

  protected

  def validate_withdrawal(amount)
    raise "Insufficient balance" if amount > @balance
  end

  private

  def secure_transaction
    # secure implementation details...
  end
end

In this example, validate_withdrawal is a protected method that can only be called from within the class. secure_transaction, on the other hand, is a private method that is only accessible within the class.

Polymorphism

Polymorphism allows objects of different classes to respond to the same messages (methods). It promotes code flexibility and extensibility. In Ruby, polymorphism is achieved through duck typing, which means that the type or class of an object is not as important as its behavior.

class Animal
  def make_sound
    raise NotImplementedError, "Subclasses must implement 'make_sound' method."
  end
end

class Cat < Animal
  def make_sound
    puts "Meow!"
  end
end

class Dog < Animal
  def make_sound
    puts "Woof!"
  end
end

In this example, both Cat and Dog are subclasses of Animal. By defining the make_sound method in each subclass, we can call it on objects of different classes:

cat = Cat.new
dog = Dog.new

cat.make_sound
# Output: Meow!

dog.make_sound
# Output: Woof!

In conclusion, Ruby's support for OOP concepts such as classes, objects, inheritance, encapsulation, and polymorphism makes it a versatile language for building robust and maintainable applications. By leveraging these concepts, developers can write clean, modular, and reusable code, leading to increased productivity and better code quality.


noob to master © copyleft