Lecture 1 / 12
Lecture 01 ยท Fundamentals

Introduction to Ruby & Setup

Beginner ~60 min

What is Ruby?

Ruby is a dynamic, open-source, object-oriented programming language created by Yukihiro "Matz" Matsumoto in the mid-90s. Unlike many other languages, Ruby was designed specifically to make programmers happy. It focuses on human-readable syntax rather than machine-readable efficiency.

If you've ever looked at code and felt it looked like a "secret code" of brackets and symbols, Ruby is the cure. It reads almost like English, which makes it one of the best languages for beginners to learn the logic of programming.

Why Learn Ruby?

  • Elegant Syntax: Ruby minimizes "boilerplate" code. You can do in 3 lines of Ruby what might take 10 lines in Java or C++.
  • Extreme Productivity: Because the language is so flexible, developers can build prototypes and full applications incredibly fast.
  • Ruby on Rails: Ruby powers Rails, one of the most influential web frameworks in history (used by Shopify, Airbnb, and GitHub).
  • Everything is an Object: This is a core concept. In Ruby, every single piece of data (even a number) is an "object," which makes the language consistent and powerful.

Installation & Environment

Installing Ruby can be tricky because most operating systems (like macOS) come with a "System Ruby" pre-installed. Warning: Never use the System Ruby for development, as it can break your OS!

Instead, we use Version Managers. These allow you to install different versions of Ruby and switch between them easily.

  • rbenv: A lightweight tool to manage Ruby versions (Highly Recommended).
  • RVM (Ruby Version Manager): A more powerful, feature-rich manager.
  • Homebrew: The standard package manager for macOS to install the tools above.
terminal
# 1. Check if Ruby is already installed
ruby --version

# 2. Enter the Interactive Ruby shell (The Playground)
irb

Meeting IRB: The Interactive Shell

Before writing full files, Ruby provides a tool called irb (Interactive Ruby). This is a "Read-Eval-Print Loop" (REPL). It allows you to type a line of code and get an instant result without having to save a file and run it.

It is the perfect place to experiment with new ideas or test a mathematical formula before putting it into your main program.

Your First Ruby Program

In Ruby, the most common way to output text to the screen is using puts (short for "put string"). Unlike print, puts automatically adds a new line after the text, making your output clean and readable.

hello.rb
# Any line starting with # is a comment and is ignored by Ruby
puts "Hello, Ruby Mastery!"
puts "Ruby is fun and productive!"
puts "Current Date: " + Time.now.to_s
Output
Hello, Ruby Mastery!
Ruby is fun and productive!
Current Date: 2024-05-20 14:30:00 +0000

๐Ÿ’ป Try It Yourself - Multi-Language Compiler

Practice Ruby and many other programming languages right here in your browser! Switch between languages, modify the code, and click "Run" to see results instantly.

๐Ÿ’ก Practice Tips:

  • Switch to Ruby in the language selector and try the web development examples
  • Experiment with Ruby's dynamic typing and metaprogramming features
  • Try other scripting languages like Python, JavaScript, or compare with PHP
  • Use the "Load Example" button to see Ruby-specific code samples
  • Use Ctrl+Enter to quickly run your code

How to run your code

To run a Ruby file, you go to your terminal and use the command ruby followed by the filename:

ruby hello.rb
๐ŸŽฏ Exercise 1.1: Ruby Basics

Complete the following steps to ensure your environment is ready:

  • 1. Install Ruby using rbenv or RVM.
  • 2. Open your terminal and type irb. Inside the shell, calculate 123 * 456 and then type exit to leave.
  • 3. Create a file named about_me.rb.
  • 4. Write a program that uses puts to print your name, your favorite hobby, and a "Fun Fact" about yourself on three separate lines.
  • 5. Run the file using the command ruby about_me.rb.
Lecture 02 ยท Fundamentals

Variables & Data Types

Beginner ~60 min

1. Understanding Variables

Think of a variable as a labeled box. You put a piece of data inside the box, and you give the box a name so you can find that data later in your program.

Ruby uses Dynamic Typing. This means you don't have to tell Ruby if a variable is a number or a piece of text; Ruby is smart enough to figure it out automatically based on the value you assign to it.

Naming Conventions

In Ruby, we use snake_case for variable names. This means all letters are lowercase, and words are separated by underscores.

variables.rb
# โœ… Correct: snake_case
user_name = "Alex"
user_age = 25
is_learning_ruby = true

# โŒ Avoid: camelCase or PascalCase (Reserved for other things in Ruby)
userName = "Alex" 
UserAge = 25 # Note: Starting with a Capital letter creates a Constant!

2. Primary Data Types

Every value in Ruby belongs to a "class" or data type. Here are the most common ones you will use:

Numbers (Integers & Floats)

Ruby handles numbers in two main ways: Integers (whole numbers) and Floats (decimal numbers).

age = 30          # Integer
pi = 3.14159      # Float
price = 19.99      # Float

Strings (Text)

Strings are sequences of characters wrapped in quotes. But Ruby has a "superpower" called String Interpolation. By using double quotes "" and the #{ } syntax, you can insert variables directly into a string.

strings.rb
name = "Sarah"

# Simple concatenation (adding strings together)
puts "Hello, " + name

# String Interpolation (The better way!)
puts "Hello, #{name}! Welcome to Ruby."

Booleans (True/False)

Booleans represent one of two states: true or false. These are used primarily for making decisions in your code (if/else statements).

is_logged_in = true
has_paid_subscription = false

Symbols

Symbols look like strings but start with a colon (e.g., :id). While a string is "data" that can change, a symbol is a unique label. They are faster for the computer to process and are used everywhere in Ruby (especially in Rails) as keys in hashes.

# String (Can be changed)
name = "Admin"

# Symbol (Immutable/Permanent label)
role = :admin

Nil (The Absence of Value)

In Ruby, nil represents "nothing" or "no value." It is not the same as zero or an empty string; it is a complete lack of a value.

user_phone_number = nil # The user didn't provide a phone number
๐ŸŽฏ Exercise 1.2: Data Type Challenge

Create a script called profile.rb that does the following:

  • Assign your name to a variable (String).
  • Assign your age to a variable (Integer).
  • Assign your height to a variable (Float).
  • Create a variable called is_student and set it to true or false.
  • Use String Interpolation to print a sentence like:
    "My name is Alex, I am 25 years old, and my height is 5.9 feet."
  • Create a symbol called :ruby_learner and print it to the console.
Lecture 03 ยท Fundamentals

Control Statements

Beginner ~75 min

What are Control Statements?

Up until now, your code has run line-by-line from top to bottom. Control Statements allow you to change that flow. They let your program make decisions: "If the user is logged in, show the dashboard; otherwise, show the login page."

This is the foundation of all logic in programming.

1. The If/Elsif/Else Structure

The if statement is the most common way to control logic. It evaluates a condition: if that condition is true, the code inside the block runs.

  • if: The primary check.
  • elsif: (Short for "else if") used to check a second or third condition if the first one was false.
  • else: The "catch-all" that runs if none of the above conditions were met.
grading_system.rb
score = 85

if score >= 90
    puts "Grade: A - Excellent!"
elsif score >= 80
    puts "Grade: B - Great job!"
elsif score >= 70
    puts "Grade: C - You passed!"
else
    puts "Grade: F - Keep practicing!"
end

2. The "Unless" Statement (The Ruby Way)

Ruby provides a unique keyword called unless. It is the exact opposite of if. It reads as: "Do this UNLESS this condition is true."

Using unless makes your code read more like a natural English sentence, which is a core goal of Ruby.

access_control.rb
is_admin = false

# This reads: "Print warning UNLESS the user is an admin"
unless is_admin
    puts "Access Denied: You do not have admin privileges."
end

3. Case Statements

When you have a single variable that could be one of many different values, using ten elsif statements becomes messy. The case statement is a cleaner, more organized alternative.

weather_app.rb
weather = "Rainy"

case weather
when "Sunny"
    puts "Wear sunscreen!"
when "Rainy"
    puts "Bring an umbrella!"
when "Snowy"
    puts "Wear a heavy coat!"
else
    puts "Check the forecast again."
end

4. The Ternary Operator (Shorthand)

For very simple "either-or" decisions, Ruby developers use the Ternary Operator. It allows you to write an if/else block in a single line.

Syntax: condition ? true_result : false_result

shorthand.rb
age = 20
# Traditional way:
if age >= 18
    status = "Adult"
else
    status = "Minor"
end

# Ternary way:
status = age >= 18 ? "Adult" : "Minor"

puts status
๐ŸŽฏ Exercise 1.3: Logic Master Challenge

Create a script called smart_home.rb that simulates a smart home system:

  • 1. Create a variable temperature (Integer) and is_raining (Boolean).
  • 2. Use an if/elsif/else block to print:
    • "Turn on Heater" if temp is below 15.
    • "Turn on AC" if temp is above 25.
    • "Temperature is perfect" otherwise.
  • 3. Use an unless statement to print "Close the windows!" only if it is raining.

  • 4. Create a variable time_of_day (e.g., "Morning", "Afternoon", "Night") and use a case statement to print a matching greeting.

  • 5. Use a Ternary Operator to check if the temperature is exactly 20 and print "Ideal" or "Not Ideal".

Lecture 04 ยท Fundamentals

Loops & Iterators

Beginner ~80 min

What are Loops?

Loops allow you to run the same block of code multiple times. Instead of writing the same line of code 10 times, you can tell Ruby to "repeat this until a condition is met" or "do this for every item in this list."

In Ruby, we divide this into two categories: Traditional Loops and Iterators.

1. Traditional Loops: While & Until

These loops are based on a condition. They keep running as long as that condition is true (or false).

  • while: Runs as long as the condition is true.
  • until: Runs until the condition becomes true (it's like a "while not" loop).
condition_loops.rb
# WHILE LOOP: Keep going while count is less than 3
count = 1
while count <= 3
    puts "While Loop: Iteration #{count}"
    count += 1 # Increment is vital to avoid infinite loops!
end

# UNTIL LOOP: Keep going until count is 6
count = 1
until count == 6
    puts "Until Loop: Iteration #{count}"
    count += 1
end

2. The "Ruby Way": Iterators

In professional Ruby code, you will rarely see while loops. Instead, Ruby uses Iterators. Iterators are methods that can be called on a collection (like an Array or a Range) to perform an action on every element.

The .times Method

If you just want to repeat a block of code a specific number of times, use .times.

5.times do |i|
    puts "This is repeat number #{i}"
end
# Note: The |i| is the index, which starts at 0

The .each Method (Most Important)

The .each method is the most used iterator in Ruby. It visits every element in a collection and passes that element into the block.

each_example.rb
friends = ["Alice", "Bob", "Charlie"]

friends.each do |friend|
    puts "Hello #{friend}, welcome to the party!"
end

Ranges and Iteration

You can combine a Range (like 1..5) with the .each method to create a loop that mimics the "for" loop from other languages.

# This will print numbers 1 through 5
(1..5).each do |num|
    puts "Processing number: #{num}"
end

3. Loop Control: Break & Next

Sometimes you need to stop a loop early or skip a specific part of it. We use break and next for this.

  • break: Exits the loop immediately.
Lecture 05 ยท Fundamentals

Methods & Blocks

Beginner ~90 min

1. Ruby Methods

A Method is a named collection of code that performs a specific task. Instead of writing the same logic five times in your program, you wrap it in a method and "call" it whenever you need it.

This makes your code DRY (Don't Repeat Yourself), which is a core principle of professional software development.

Defining and Calling Methods

In Ruby, we define a method using the def keyword and end it with the end keyword.

basic_methods.rb
# Defining a simple method with no arguments
def greet_world
    puts "Hello! Welcome to the Ruby world!"
end

# Calling the method
greet_world # Output: Hello! Welcome to the Ruby world!

Arguments & Parameters

Methods become powerful when you pass data into them. These are called arguments.

# 'name' and 'time_of_day' are parameters
def personalized_greet(name, time_of_day)
    puts "Good #{time_of_day}, #{name}!"
end

personalized_greet("Sarah", "Morning") # Output: Good Morning, Sarah!
personalized_greet("Alex", "Evening")   # Output: Good Evening, Alex!

Implicit Returns

One of Ruby's most famous features is the Implicit Return. In many languages, you must use a return statement to send a value back. In Ruby, the last line of a method is automatically returned as the result.

# This method calculates a total
def add_tax(price)
    total = price * 1.15
    total # This is the last line, so it is returned automatically
end

result = add_tax(100)
puts result # Output: 115.0

2. Understanding Blocks

A Block is a chunk of code that you can pass into a method as an argument. It's like giving a method a "mini-program" to run inside itself.

Blocks are usually wrapped in do ... end or curly braces { ... }.

The Magic of yield

If you want to create a method that accepts a block, you use the yield keyword. When Ruby hits yield, it pauses the method, runs the code inside the block, and then comes back to finish the method.

block_magic.rb
# A method that accepts a block
def repeat_action
    puts "Starting the action..."
    yield # This is where the block code will be executed
    puts "Action completed!"
end

# Calling the method and passing a block
repeat_action do
    puts "I am currently inside the block!"
    puts "Doing some hard work..."
end

Passing Data to Blocks

You can pass data from the method into the block by adding values to yield. The block receives these values inside pipes |variable|.

# This is essentially how .each works behind the scenes!
def custom_looper(items)
    items.each do |item|
        yield(item) # Send the current item into the block
    end
end

my_list = ["Ruby", "Python", "Java"]

custom_looper(my_list) do |lang|
    puts "I am learning #{lang}!"
end
๐ŸŽฏ Exercise 1.5: The Method & Block Challenge

Create a script called calculator_pro.rb and complete these tasks:

  • 1. Create a method called calculate_total that takes price and quantity and returns the total cost.
  • 2. Create a method called apply_operation. This method should take two numbers and a block. Inside the method, use yield to pass those two numbers into the block.
  • 3. Call apply_operation three different times, passing a different block each time to:
    • Sum the two numbers.
    • Multiply the two numbers.
    • Subtract the second number from the first.
  • 4. Print the results of all three operations using puts.
Lecture 06 ยท Core Concepts

Arrays & Hashes

Beginner ~45 min

Arrays and Hashes are two of the most important data structures in Ruby. They help developers organize, store, and manage data efficiently in applications.

Arrays are used for storing ordered collections of values, while Hashes store data in key-value pairs. Both are heavily used in Ruby programming, web development, APIs, and database operations.

Arrays

An Array is a collection of multiple values stored inside a single variable. Each element inside the array has an index position starting from 0.

Arrays can store numbers, strings, objects, or even other arrays.

arrays.rb
arr = [1, 2, 3, 4, 5]

arr << 6

arr.each { |n| puts n }

arr.map { |n| n * 2 }

arr.select { |n| n.even? }

In this example:

  • [1, 2, 3, 4, 5] creates an array
  • << adds a new element to the array
  • each loops through every element
  • map transforms array values
  • select filters elements based on conditions

Accessing Array Elements

Array elements can be accessed using index positions. Remember that indexing starts from zero.

access.rb
fruits = ["Apple", "Banana", "Orange"]

puts fruits[0]
puts fruits[1]

Output:

Apple
Banana

Here:

  • fruits[0] accesses the first element
  • fruits[1] accesses the second element

Adding and Removing Elements

Ruby provides several methods for modifying arrays dynamically.

modify.rb
numbers = [1, 2, 3]

numbers.push(4)

numbers.pop

puts numbers.inspect

Explanation:

  • push() adds an element to the end of the array
  • pop removes the last element
  • inspect displays the complete array

Looping Through Arrays

Looping allows us to process each element individually. Ruby provides elegant iteration methods for arrays.

loop.rb
colors = ["Red", "Green", "Blue"]

colors.each do |color|
  puts color
end

The each method is one of the most commonly used iteration methods in Ruby.

Transforming Arrays with map()

The map() method creates a new array by modifying each element.

map.rb
numbers = [1, 2, 3]

doubled = numbers.map { |n| n * 2 }

puts doubled.inspect

Output:

[2, 4, 6]

Filtering Arrays with select()

The select() method filters elements based on conditions.

select.rb
numbers = [1, 2, 3, 4, 5]

evens = numbers.select { |n| n.even? }

puts evens.inspect

Output:

[2, 4]

Hashes

A Hash is a collection of key-value pairs. Instead of numeric indexes, data is accessed using unique keys.

Hashes are extremely useful for storing structured data such as user profiles, configuration settings, and JSON-like objects.

hashes.rb
user = { name: "Ahmed", age: 25 }

user[:city] = "Cairo"

user.each { |k, v| puts "#{k}: #{v}" }

In this example:

  • name and age are keys
  • "Ahmed" and 25 are values
  • user[:city] adds a new key-value pair
  • each iterates through the hash

Accessing Hash Values

Hash values are accessed using keys.

access_hash.rb
student = {
  name: "Sara",
  marks: 92
}

puts student[:name]
puts student[:marks]

Output:

Sara
92

Updating Hashes

Hash values can easily be updated or modified.

update.rb
user = { name: "Ali", age: 20 }

user[:age] = 21

puts user.inspect

The age value changes from 20 to 21.

Nested Arrays and Hashes

Ruby allows arrays and hashes to be nested inside each other for more complex data structures.

nested.rb
students = [
  { name: "Ahmed", grade: 90 },
  { name: "Sara", grade: 85 }
]

puts students[0][:name]

This structure is commonly used in APIs and database records.

Advantages of Arrays & Hashes

  • Efficient data organization
  • Easy data access and modification
  • Flexible storage structures
  • Useful for real-world applications
  • Essential for Ruby and Rails development

Best Practices

  • Use arrays for ordered collections
  • Use hashes for structured key-value data
  • Choose meaningful key names
  • Avoid deeply nested structures when possible
  • Use iteration methods for cleaner code
Practice

Create a hash of students with grades, find all with grade > 80.

Try adding:

  • At least 5 students
  • A loop to display student names
  • A condition to filter high grades
  • An average grade calculator

Summary

In this lecture, we learned about Arrays and Hashes in Ruby. We explored how arrays store ordered collections and how hashes store data using key-value pairs.

We also learned how to access, modify, transform, and filter data using methods like each, map, and select.

Arrays and Hashes are foundational concepts used throughout Ruby programming and Ruby on Rails development.

Lecture 07 ยท Core Concepts

Strings & Regular Expressions

Intermediate ~45 min

Strings are one of the most commonly used data types in programming. Almost every application works with text in some form โ€” usernames, passwords, emails, search queries, messages, logs, and file content.

Ruby provides powerful built-in string methods that make text processing simple and efficient. Along with strings, Ruby also supports Regular Expressions (Regex), which allow developers to search, validate, and manipulate text patterns.

In this lecture, we will learn:

  • How to work with strings in Ruby
  • Important string methods
  • How string manipulation works
  • What regular expressions are
  • How regex is used for validation and searching

String Methods

Ruby strings come with many built-in methods for modifying and analyzing text. These methods help developers process data quickly without writing complex logic.

strings.rb
s = "Hello Ruby"

# Convert to uppercase
puts s.upcase

# Convert to lowercase
puts s.downcase

# Reverse string
puts s.reverse

# String length
puts s.length

# Replace text
puts s.gsub("Ruby", "World")

# Split into array
p s.split(" ")

Understanding Important String Methods

  • upcase converts text to uppercase
  • downcase converts text to lowercase
  • reverse reverses characters
  • length returns total characters
  • gsub replaces text globally
  • split breaks string into arrays

More Useful String Methods

Ruby includes many additional methods for checking and manipulating text.

more_strings.rb
text = "  Ruby Language  "

# Remove spaces
puts text.strip

# Check substring
puts text.include?("Ruby")

# Start and end checks
puts text.start_with?(" ")
puts text.end_with?(" ")

# Repeat string
puts "Hi! " * 3

# Access characters
puts text[2]
puts text[0, 5]

String Interpolation

String interpolation allows variables to be inserted directly inside strings using #{ }.

This is cleaner and easier than concatenation.

interpolation.rb
name = "Ahmed"
age = 22

puts "My name is #{name}"
puts "I am #{age} years old"

Regular Expressions (Regex)

Regular Expressions are patterns used to search, match, and validate text. Regex is extremely useful for checking formats like emails, phone numbers, passwords, URLs, and dates.

Ruby provides excellent built-in support for regex.

regex.rb
# Match digits
puts "abc123" =~ /\d+/

# Email validation
puts "a@b.com".match?(/\A[\w.]+@[\w]+\.\w+\z/)

# Find all matches
p "hello".scan(/l/)

Understanding Regex Symbols

  • \d โ†’ Any digit
  • + โ†’ One or more matches
  • \A โ†’ Start of string
  • \z โ†’ End of string
  • [] โ†’ Character group
  • . โ†’ Any character

Regex Matching Methods

Ruby provides several methods for regex operations.

regex_methods.rb
text = "Ruby 123 Programming"

# Check match
puts text.match?(/\d+/)

# Return first match
p text.match(/\d+/)

# Find all matches
p text.scan(/\w+/)

# Replace using regex
puts text.gsub(/\d+/, "***")

Email Validation Example

Regex is commonly used for validating user input in forms and applications.

email_validator.rb
email = "user@example.com"

pattern = /\A[\w.]+@[\w]+\.\w+\z/

if email.match?(pattern)
  puts "Valid Email"
else
  puts "Invalid Email"
end

Phone Number Validation

Regex can also validate phone number formats.

phone_regex.rb
phone = "9876543210"

if phone.match?(/\A\d{10}\z/)
  puts "Valid Number"
else
  puts "Invalid Number"
end

Common Regex Patterns

patterns.rb
# Only digits
/\d+/

# Only alphabets
/[a-zA-Z]+/

# Whitespace
/\s/

# Email format
/\A[\w.]+@[\w]+\.\w+\z/

# 10-digit phone number
/\A\d{10}\z/

Best Practices

  • Use meaningful regex patterns
  • Keep regex readable and simple
  • Use string methods before complex regex when possible
  • Validate user input carefully
  • Test regex patterns with multiple examples
Practice

Create Ruby programs that:

  • Validate phone numbers using regex
  • Validate email addresses
  • Count words inside a sentence
  • Replace digits with symbols
  • Check if a password contains numbers
Lecture 08 ยท Core Concepts

OOP in Ruby

Intermediate ~45 min

Object-Oriented Programming (OOP) is a programming paradigm that organizes code using objects and classes. Ruby is a fully object-oriented language, meaning almost everything in Ruby is treated as an object.

OOP helps developers write cleaner, reusable, scalable, and maintainable code. It is widely used in Ruby on Rails applications and modern software development.

What is a Class?

A class is a blueprint or template used to create objects. It defines the properties (attributes) and behaviors (methods) that objects will have.

For example:

  • A Car class may contain color, speed, and brand
  • A User class may contain name, email, and password
  • A BankAccount class may contain balance and account number

Classes

class.rb
class Person

  attr_accessor :name, :age

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

  def greet = "Hi, I'm #{@name}"
end

p = Person.new("Ahmed", 25)

puts p.greet

In this example:

  • class Person defines a new class
  • attr_accessor creates getter and setter methods
  • initialize is the constructor method
  • @name and @age are instance variables
  • Person.new() creates a new object
  • greet is an instance method

Understanding Objects

An object is an instance of a class. When we create an object, Ruby allocates memory and stores the object's data separately.

objects.rb
car1 = Person.new("Ali", 22)

car2 = Person.new("Sara", 21)

puts car1.name
puts car2.name

Each object maintains its own independent data.

Instance Variables

Instance variables store object-specific data. They begin with the @ symbol.

instance.rb
class Student

  def initialize(name)
    @name = name
  end

  def show
    puts @name
  end
end

The variable @name belongs to each individual object.

Methods in Ruby

Methods define the behavior of objects. They allow objects to perform actions.

methods.rb
class Calculator

  def add(a, b)
    a + b
  end
end

calc = Calculator.new

puts calc.add(5, 3)

Output:

8

Accessors in Ruby

Ruby provides special helper methods for managing object attributes.

  • attr_reader โ†’ Read-only access
  • attr_writer โ†’ Write-only access
  • attr_accessor โ†’ Read and write access
accessor.rb
class User

  attr_accessor :username

  def initialize(username)
    @username = username
  end
end

Inheritance

Inheritance allows one class to inherit properties and methods from another class. This promotes code reusability and reduces duplication.

inherit.rb
class Animal

  def speak = "..."
end

class Dog < Animal

  def speak = "Woof!"
end

In this example:

  • Dog inherits from Animal
  • The speak method is overridden inside Dog
  • This demonstrates polymorphism in Ruby

Method Overriding

Method overriding occurs when a child class provides its own version of a parent class method.

override.rb
class Vehicle

  def move
    puts "Moving..."
  end
end

class Bike < Vehicle

  def move
    puts "Bike is moving"
  end
end

Using super

The super keyword calls a method from the parent class.

super.rb
class Animal

  def speak
    puts "Animal sound"
  end
end

class Cat < Animal

  def speak
    super
    puts "Meow"
  end
end

Output:

Animal sound
Meow

Encapsulation

Encapsulation means hiding internal object details and exposing only necessary functionality. It improves security and protects object data.

private.rb
class Account

  def show_balance
    puts calculate_balance
  end

  private

  def calculate_balance
    5000
  end
end

Private methods can only be accessed inside the same class.

Advantages of OOP

  • Improves code organization
  • Encourages code reusability
  • Makes large applications easier to manage
  • Supports modular development
  • Reduces duplicate code

Real-World Uses of OOP

  • Web applications
  • Game development
  • Banking systems
  • E-commerce platforms
  • Social media applications
  • Desktop software

Best Practices

  • Use meaningful class names
  • Keep classes focused on one responsibility
  • Avoid unnecessary inheritance
  • Use encapsulation to protect data
  • Write reusable methods
Practice

Create a BankAccount class with deposit/withdraw.

Try adding:

  • A balance instance variable
  • A method to check account balance
  • Error handling for insufficient funds
  • A transaction history array

Summary

In this lecture, we learned the fundamentals of Object-Oriented Programming in Ruby. We explored classes, objects, methods, instance variables, and accessors.

We also studied inheritance, method overriding, encapsulation, and the use of the super keyword.

OOP is a foundational concept in Ruby and is heavily used in Ruby on Rails and modern software development.

Lecture 09 ยท Core Concepts

Modules & Mixins

Intermediate ~45 min

As Ruby applications grow larger, organizing code becomes extremely important. Writing everything inside a single file or class quickly becomes difficult to manage.

Ruby provides Modules and Mixins to help developers organize reusable code efficiently. Modules help group related functionality together, while mixins allow classes to share methods without inheritance.

These concepts are widely used in Ruby and Ruby on Rails applications because they improve:

  • Code organization
  • Reusability
  • Maintainability
  • Scalability

In this lecture, we will learn:

  • What modules are
  • How modules work as namespaces
  • How to create reusable mixins
  • How include works in Ruby
  • How modules improve application structure

What is a Module?

A module is a container used to group related methods, constants, and classes together. Unlike classes, modules cannot create objects directly.

Modules are mainly used for:

  • Creating namespaces
  • Sharing reusable functionality
  • Avoiding naming conflicts

Modules as Namespaces

Namespaces prevent naming conflicts between classes and methods. In large applications, different files may contain methods or classes with the same name.

Modules solve this problem by grouping related functionality together.

module.rb
module MathTools

  # Module method
  def self.square(x)
    x * x
  end
end

puts MathTools.square(5)

Understanding the Example

  • module MathTools creates a namespace
  • self.square defines a module method
  • MathTools.square(5) calls the method

Another Namespace Example

Multiple classes with the same name can exist safely inside different modules.

namespace.rb
module Admin

  class User

    def info
      puts "Admin User"
    end
  end
end

module Customer

  class User

    def info
      puts "Customer User"
    end
  end
end

Admin::User.new.info

Customer::User.new.info

Why Namespaces Are Important

  • Avoid duplicate names
  • Improve project organization
  • Group related functionality
  • Keep code cleaner

Mixins

Mixins allow methods from a module to be included inside a class. This is one of Rubyโ€™s most powerful features.

Instead of inheriting from another class, Ruby allows classes to reuse functionality through modules.

mixin.rb
module Loggable

  def log(msg)
    puts "[LOG] #{msg}"
  end
end

class Service

  include Loggable

  def run
    log("Started")
  end
end

Service.new.run

Understanding Mixins

  • Loggable contains reusable methods
  • include adds module methods to the class
  • Service can directly use the log() method

Benefits of Mixins

  • Reduce duplicate code
  • Share reusable behaviors
  • Support cleaner architecture
  • Avoid deep inheritance chains

Including Multiple Modules

A Ruby class can include multiple modules at the same time.

multi_mixin.rb
module Printer

  def print_data
    puts "Printing Data"
  end
end

module Scanner

  def scan_data
    puts "Scanning Data"
  end
end

class Machine

  include Printer
  include Scanner
end

m = Machine.new

m.print_data

m.scan_data

Using extend

Ruby also provides the extend keyword. While include adds methods as instance methods, extend adds methods as class methods.

extend.rb
module Greeting

  def hello
    puts "Hello"
  end
end

class Test

  extend Greeting
end

Test.hello

include vs extend

  • include โ†’ Adds instance methods
  • extend โ†’ Adds class methods

Ruby Built-in Mixins

Ruby includes several built-in modules that provide useful functionality.

comparable.rb
class Product

  include Comparable

  attr_accessor :price

  def initialize(price)
    @price = price
  end

  def <=>(other)
    price <=> other.price
  end
end

p1 = Product.new(100)

p2 = Product.new(200)

puts p1 < p2

What is Comparable?

The Comparable module allows objects to be compared using operators like:

  • <
  • >
  • <=
  • >=
  • ==

To use Comparable, a class must define the <=> spaceship operator.

Best Practices

  • Use modules to organize related functionality
  • Use mixins for reusable behaviors
  • Avoid putting too many responsibilities in one module
  • Prefer mixins over unnecessary inheritance
  • Use namespaces in large projects
Practice

Create the following:

  • A Comparable mixin for a Book class
  • A Logger module with reusable log methods
  • Two namespaces containing classes with the same name
  • A class that includes multiple mixins
Lecture 10 ยท Advanced

File I/O & Exceptions

Intermediate~45 min

Reading & Writing

files.rb
File.read("input.txt")
File.readlines("input.txt").each { |l| puts l }
File.open("out.txt", "w") { |f| f.puts "Hello" }
File.open("out.txt", "a") { |f| f.puts "World" }

Exceptions

errors.rb
begin
  File.read("missing.txt")
rescue Errno::ENOENT => e
  puts "Not found: #{e}"
ensure
  puts "Done."
end
Practice

Write a CSV parser that handles missing files gracefully.

Lecture 11 ยท Advanced

Metaprogramming

Advanced~45 min

Dynamic Methods

meta.rb
class User
  [:name, :age, :email].each do |attr|
    define_method(attr) { instance_variable_get("@#{attr}") }
    define_method("#{attr}=") { |v| instance_variable_set("@#{attr}", v) }
  end
end

method_missing

missing.rb
class Ghost
  def method_missing(method, *args)
    puts "Called #{method} with #{args}"
  end
end
Practice

Build find_by_name, find_by_age dynamic methods.

Lecture 12 ยท Advanced

Gems & Bundler

Intermediate~45 min

Gemfile

Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.0'
gem 'rspec', group: :test

Commands

cmd.sh
gem install nokogiri
bundle install
bundle update
bundle exec rake test
Practice

Create a Bundler project, install httparty, fetch a URL.

Lecture 13 ยท Advanced

Testing with RSpec

Intermediate~45 min

Basic Spec

calc_spec.rb
require 'rspec'
describe Calculator do
  it "adds two numbers" do
    expect(Calculator.add(2, 3)).to eq(5)
  end
end

Mocks

mock.rb
api = double("API")
allow(api).to receive(:fetch).and_return("data")
expect(api.fetch).to eq("data")
Practice

Write 5 specs for a Stack class (push, pop, peek, empty?, size).

Lecture 14 ยท Rails

Rails Basics

Advanced~45 min

Create a Rails App

setup.sh
gem install rails
rails new blog
cd blog
rails server

MVC Pattern

Rails follows Model-View-Controller: Models talk to the DB, Controllers handle requests, Views render HTML/JSON.

Scaffold a Resource

scaffold.sh
rails generate scaffold Post title:string body:text
rails db:migrate
rails server
Practice

Scaffold a Book resource with title and author.

Lecture 15 ยท Rails

Models & ActiveRecord

Advanced~45 min

Model Definition

post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments
  validates :title, presence: true, length: { minimum: 5 }
end

Queries

queries.rb
Post.all
Post.find(1)
Post.where(published: true).order(created_at: :desc)
Post.create(title: "Hello", body: "World")
post.update(title: "New")
post.destroy

Migrations

migration.rb
class AddAuthorToPosts < ActiveRecord::Migration[7.0]
  def change
    add_column :posts, :author, :string
  end
end
Practice

Create a User-Post-Comment relationship with validations.

Lecture 16 ยท Rails

Controllers & Routes

Advanced~45 min

Routes

routes.rb
Rails.application.routes.draw do
  root "posts#index"
  resources :posts
  get "/about", to: "pages#about"
end

Controller

posts_controller.rb
class PostsController < ApplicationController
  def index = @posts = Post.all
  def show = @post = Post.find(params[:id])
  def create
    @post = Post.new(post_params)
    @post.save ? redirect_to(@post) : render(:new)
  end
  private
  def post_params
    params.require(:post).permit(:title, :body)
  end
end
Practice

Build full CRUD routes and controller for a Book resource.

Lecture 17 ยท Rails

APIs & Deployment

Advanced~45 min

API Mode

api.sh
rails new myapi --api
# Controllers return JSON automatically
posts_controller.rb
class Api::PostsController < ApplicationController
  def index
    render json: Post.all
  end
  def create
    post = Post.create!(post_params)
    render json: post, status: :created
  end
end

Deploy to Heroku/Render

deploy.sh
git push heroku main
heroku run rails db:migrate
heroku logs --tail
Practice

Build a JSON API for a Todo list, deploy to Render.com.

Lecture 18 ยท Rails

Capstone Project: Rails Blog

Advanced~60 min

Project: Full Blog Platform

Build a complete Rails blog with authentication, posts, comments, tags, and admin dashboard.

Features

  • User auth (Devise gem)
  • Posts with categories & tags
  • Comments with nested replies
  • Admin dashboard
  • Rich text editor (ActionText)
  • Image uploads (ActiveStorage)

Stack

Gemfile
gem 'rails', '~> 7.0'
gem 'devise'
gem 'pg'
gem 'image_processing'
gem 'rspec-rails', group: :test

Bonus

  • Add markdown support with Redcarpet
  • Add full-text search with pg_search
  • Build a JSON API for mobile
  • Deploy with Docker + CI/CD
Final Challenge

Build the full blog. Deploy it. Share the GitHub repo!