Object-Oriented Programming (OOP) with Ruby on Rails
Tags: ruby, rails, oop, beginners
Published: 2023-08-15 00:32:03

# Introduction

Object-Oriented Programming (OOP) is a programming paradigm that's based on the concept of "objects," which encapsulate both data and methods that operate on that data. Ruby on Rails, a widely used web framework, embraces the OOP philosophy.

In this article, we'll build a vending machine using the principles of OOP in Ruby on Rails. A vending machine is a great example to illustrate the OOP concepts as it involves various objects and interactions among them.


# What is OOP?
Object-Oriented Programming (OOP) is a programming paradigm that uses objects and classes to organize code into reusable and modular components. The core concepts of OOP include:

- Encapsulation: Enclosing data (variables) and code (methods) into a single unit called an object. This helps in hiding the internal structure and protects the integrity of the data.

- Inheritance: The ability for one class to inherit properties and behavior from another class. This promotes code reusability and a logical hierarchy among objects.

- Polymorphism: Allowing objects to be treated as instances of their own class or any of its parent classes. This leads to flexible code that can handle different data types and structures.

- Abstraction: Creating simple interfaces that allow you to interact with more complex underlying code. It hides the complex reality while exposing only essential parts.

By applying OOP concepts, we can create code that is more maintainable, scalable, and easier to understand.


# Understanding the Problem

A vending machine is an automated machine that provides items such as snacks, beverages, and cigarettes to consumers after money is inserted into the machine.

We need to model the following:

- Selection of items
- Acceptance of money
- Dispensing of items
- Returning change if necessary


# Designing the Objects

We'll need a few classes to represent the different components of the vending machine:

1. Product: Represents the individual items that the machine sells.
2. Inventory: Manages the stack of products within the machine.
3. MoneyHandler: Manages the acceptance and dispensing of money.
4. VendingMachine: The main class that ties everything together.


# Implementation

Here's how we can code these classes:

- Product class
The `Product` class represents the individual items that the machine sells. It has attributes for the name and price of the product.
```ruby
class Product
  atter_reader :name, ;price

  def initialize(name, price)
    @name = name
    @price = price
  end
end
```

- Inventory class
The `Inventory` class manages the stock of products within the machine. You can add a product with its quantity to the inventory.
```ruby
class Inventory
  attr_accessor :products

  def initialize
    @products = []
  end

  def add_product(product, quantity)
    quantity.times { @products << product }
  end
end
```

- MoneyHandler class
The `MoneyHnadler` class manages the acceptance and dispensing of money, including the current balance.
```ruby
class MoneyHandler
  attr_accessor :balance

  def initialize(amount)
    @balance = 0
  end

  def insert_money(amount)
    @balance += amount
  end

  def deduct_money(amount)
    @balance -= amount
  end
end
```

- VendingMachine
The `VendingMachine` class integrates the other classes and handles the main functionality of selecting products, accepting money, dispensing items, and returning changes.
```ruby
class VendingMachine
  def initialize
    @inventory = Inventory.new
    @money_handler = MoneyHandler.new
    @selected_product = nil
  end

  def select_product(product_name)
    @selected_product = @inventory.products.keys.find { |product| product.name == product_name }
  end

  def insert_money(amount)
    @money_handler.insert_money(amount)
  end

  def purchase
    if @seleccted_product && @money_handler.balance >= @selected_product.price
      @money_handler.deduct_money(@selected_product.price)
      @inventory.remove_product(@selected_product)
      return "Successfully purchased #{@selected_product.name}"
    else
      return "Insufficient funds or product not selected."
    end
  end

  def return_change
    change = @money_handler.balance
    @money_handler.balance = 0
    return "Change returned: #{change}."
  end
end
```


# Usage Example
Now you can create instances of these classes and interact with them.
```ruby
cola = Product.new("Cola", 1.50)
vending_machine = VendingMachine.new
vending_machine.select_product("Cola")
vending_machine.insert_money(2)
puts vending_machine.purchase # Output: Successfully purchased Cola.
puts vending_machine.return_change # Output: Change returned: 0.5.
```


# Conclusion
The above code fully models a basic vending machine using OOP concepts in Ruby. By dividing the responsibilities among different classes (`Product`, `Inventory`, `MoneyHandler`, and `VendingMachine`), the code is more maintainable and easier to understand.

This structure allows you to further extend the functionality, such as adding more detailed inventory management, support for different payment methods, or more complex user interaction.