Ruby and Object Oriented Programing
Published: 2023-06-07 17:20:44

For today's topic we will discuss the Ruby programming language and how it's object-oriented approach makes it fun and happy for programmers to use. 

## Ruby

Ruby is a dynamic object-oriented, general-purpose programming language designed and developed in the mid-1990s by Yukihiro "Matz" Matsumoto in Japan. Matz designed Ruby for programmers in mind so that programming should be happy and fun. 

Coming from "Matz"

> The goal of Ruby is to make programmers happy. I started out to make a programming language that would make me happy, and as a side effect it’s made many, many programmers happy.

> I hope to see Ruby help every programmer in the world to be productive, and to enjoy programming, and to be happy. That is the primary purpose of Ruby language.

> — Yukihiro Matsumoto

## Objects in Ruby

How does Ruby accomplish this task you may ask. Well one of the core concepts of the Ruby language is that fact it sees everything as an object. This means that every bit of information and code can be given their own properties and actions. Through Ruby's object-oriented approach we call properties by the name instance variables and actions are known as methods.

To create an object in Ruby, you first define a class, which serves as a blueprint or template for creating objects. The class specifies the data (instance variables) and behavior (instance methods) that objects of that class will have. Once the class is defined, you can create objects or instances of that class.

```
class Person
  def initialize(name, age)
    @name = name
    @age = age
  end

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

person1 = Person.new("Alice", 25)
person1.greet #=> Hello, my name is Alice and I'm 25 years old.

person2 = Person.new("Bob", 30)
person2.greet #=> Hello, my name is Bob and I'm 30 years old.

```

In this example, the Person class represents a person and has an initialize method that takes the name and age as parameters. The initialize method is automatically called when a new object is created using the new method.

We create two objects (person1 and person2) using the Person.new syntax and pass the name and age as arguments. Each object has its own separate set of instance variables (@name and @age) initialized with the provided values.

We can then call the greet method on each object using the dot notation. The greet method accesses the instance variables @name and @age to display a greeting specific to each person.

## Ruby's  Flexibility 

In addition to Ruby's object-oriented approach, Ruby is extremely flexible to code in since it allows its users to freely alter its parts. Essential parts of Ruby can be removed or redefined, at will. Existing parts can be added upon. Ruby tries not to restrict the coder. Ruby's block help increase it's flexibility since a programmer can attach a closure to any method to describe how that method should act.

In Ruby, block helper methods are a way to define methods that accept a block of code as an argument. These methods can execute the block of code within their implementation, allowing for more flexible and dynamic behavior.

Block helper methods are commonly used in Ruby for tasks like iterating over collections, performing conditional operations, and executing custom logic. They provide a powerful way to encapsulate and reuse code.

```
def greet
  puts "Hello!"
  yield if block_given?
  puts "Goodbye!"
end

greet do
  puts "Nice to meet you!"
end

```
In this example, we define a method called greet that prints "Hello!" and "Goodbye!", with the yield keyword used to execute a block of code if it is given. The yield statement acts as a placeholder for the block.

When we invoke greet and provide a block of code (do ... end), the code within the block is executed between the "Hello!" and "Goodbye!" messages. In this case, it prints "Nice to meet you!".

Block helper methods can also accept parameters and pass them to the block.


```
def repeat(n)
  n.times do |i|
    yield i
  end
end

repeat(3) do |i|
  puts "Iteration #{i+1}"
end

```

In this example, the repeat method takes an integer n as a parameter. It then executes the block n times, passing the iteration index (i) to the block. The block prints the current iteration number.

When we invoke repeat(3) and provide a block, the block is executed three times, printing "Iteration 1", "Iteration 2", and "Iteration 3".

Block helper methods are widely used in Ruby, and they provide a flexible way to extend the behavior of methods and create reusable code patterns. They are especially useful for tasks that require iterating, filtering, transforming, or performing custom logic on collections or data structures.

## Ruby Inheritance

Finally, unlike many other object-oriented languages Ruby features single inheritance but understands the concept of modules which are a collection of methods. Classes can include different modules that gives them access to all the methods from that module for free.

Inheritance is a fundamental concept in object-oriented programming that allows a class to inherit attributes and behaviors from another class. In Ruby, you can create a subclass that inherits from a superclass using the inheritance mechanism.

To define a subclass that inherits from a superclass, you use the < symbol followed by the name of the superclass. The subclass inherits all the instance variables, instance methods, and class methods of the superclass.

```
class Animal
  def breathe
    puts "I'm breathing!"
  end
end

class Mammal < Animal
  def feed_offspring
    puts "I'm feeding my offspring."
  end
end

dog = Mammal.new
dog.breathe #=> I'm breathing!
dog.feed_offspring #=> I'm feeding my offspring.

```

In this example, we have a superclass called Animal that defines an instance method breathe. We then define a subclass called Mammal that inherits from Animal using the < symbol.

The Mammal subclass inherits the breathe method from the Animal superclass. Additionally, we define a new instance method feed_offspring specific to the Mammal class.

We create an instance of Mammal called dog and can call both the inherited method breathe and the specific method feed_offspring on that instance.

Inheritance allows subclasses to reuse and extend the behavior defined in their superclass. Subclasses can add new methods, override existing methods, and access the inherited methods and instance variables.

In Ruby, single inheritance is supported, meaning a class can inherit from only one superclass. However, you can create a hierarchy of classes with multiple levels of inheritance, where subclasses can themselves become superclasses for other subclasses.

```
class Animal
  def breathe
    puts "I'm breathing!"
  end
end

class Mammal < Animal
  def feed_offspring
    puts "I'm feeding my offspring."
  end
end

class Dog < Mammal
  def bark
    puts "Woof woof!"
  end
end

dog = Dog.new
dog.breathe #=> I'm breathing!
dog.feed_offspring #=> I'm feeding my offspring.
dog.bark #=> Woof woof!

```
In this updated example, we introduce a new subclass called Dog that inherits from Mammal. The Dog class adds its own instance method bark.

Now, the Dog class inherits the methods breathe and feed_offspring from its superclass Mammal and can also call its own method bark. This demonstrates the hierarchical nature of inheritance, where subclasses inherit from their immediate superclass and all the way up the inheritance chain.

Inheritance is a powerful mechanism that promotes code reuse and allows for creating class hierarchies, where classes can share common behaviors while adding their own specific characteristics.

From what we have discussed, you can see why programmers enjoy working in Ruby.