Skip to content

Instantly share code, notes, and snippets.

@kwhandy
Last active July 25, 2025 06:53
Show Gist options
  • Select an option

  • Save kwhandy/b2fcfad4db468d8b4a4448344be0cde0 to your computer and use it in GitHub Desktop.

Select an option

Save kwhandy/b2fcfad4db468d8b4a4448344be0cde0 to your computer and use it in GitHub Desktop.
understand ruby from business background
# Computer Science Concepts for Business People
# Using Trading, Business, and Monopoly Analogies in Ruby
puts "=" * 60
puts "PART 1: BASIC DATA STRUCTURES"
puts "=" * 60
# ==========================================
# 1. ARRAYS - Like a Filing Cabinet
# ==========================================
puts "\n1. ARRAYS - Your Company's Filing Cabinet"
puts "-" * 40
# Think of an array as a filing cabinet with numbered drawers
# Each drawer (index) holds exactly one document (value)
# You can access any drawer directly if you know its number
company_departments = ["Sales", "Marketing", "Finance", "HR", "IT"]
puts "Our company departments (array):"
company_departments.each_with_index do |dept, index|
puts " Drawer #{index}: #{dept}"
end
# Adding a new department (like hiring a new division)
company_departments << "Legal"
puts "\nAfter adding Legal department: #{company_departments}"
# Accessing specific department (like going to drawer #2)
puts "Department in drawer 2: #{company_departments[2]}"
# Business analogy: Arrays are like employee ID systems
# Employee ID 0 = First employee, ID 1 = Second employee, etc.
employee_salaries = [50000, 60000, 75000, 80000, 90000]
puts "Employee #2's salary: $#{employee_salaries[2]}"
# ==========================================
# 2. LINKED LISTS - Like a Supply Chain
# ==========================================
puts "\n2. LINKED LISTS - Your Supply Chain Network"
puts "-" * 40
# A linked list is like a supply chain where each supplier
# knows only about the next supplier in the chain
class Supplier
attr_accessor :company_name, :next_supplier
def initialize(name)
@company_name = name
@next_supplier = nil
end
end
# Creating our supply chain
raw_materials = Supplier.new("Raw Materials Co")
manufacturer = Supplier.new("Manufacturing Inc")
distributor = Supplier.new("Distribution LLC")
retailer = Supplier.new("Retail Store")
# Linking the chain (each supplier points to the next)
raw_materials.next_supplier = manufacturer
manufacturer.next_supplier = distributor
distributor.next_supplier = retailer
puts "Supply chain flow:"
current = raw_materials
while current
puts " #{current.company_name}"
if current.next_supplier
puts " ↓ (ships to)"
end
current = current.next_supplier
end
# ==========================================
# 3. STACKS - Like a Stack of Invoices
# ==========================================
puts "\n3. STACKS - Your Invoice Processing Stack"
puts "-" * 40
# A stack works like a pile of invoices on your desk
# Last invoice you put on top is the first one you process (LIFO)
invoice_stack = []
# Adding invoices (pushing onto stack)
puts "Adding invoices to process:"
["Invoice #001", "Invoice #002", "Invoice #003"].each do |invoice|
invoice_stack.push(invoice)
puts " Added: #{invoice} (stack: #{invoice_stack})"
end
# Processing invoices (popping from stack)
puts "\nProcessing invoices (most recent first):"
while !invoice_stack.empty?
current_invoice = invoice_stack.pop
puts " Processing: #{current_invoice}"
end
# Real business example: Undo functionality in software
action_history = []
action_history.push("Created report")
action_history.push("Added chart")
action_history.push("Changed colors")
puts "\nUndo last action: #{action_history.pop}"
puts "Remaining actions: #{action_history}"
# ==========================================
# 4. QUEUES - Like Customer Service Line
# ==========================================
puts "\n4. QUEUES - Your Customer Service Line"
puts "-" * 40
# A queue is like a customer service line
# First customer in line gets served first (FIFO)
customer_queue = []
# Customers joining the line (enqueue)
puts "Customers joining the service line:"
["Alice", "Bob", "Charlie", "Diana"].each do |customer|
customer_queue.push(customer) # Add to back of line
puts " #{customer} joined the line (queue: #{customer_queue})"
end
# Serving customers (dequeue)
puts "\nServing customers (first come, first served):"
while !customer_queue.empty?
current_customer = customer_queue.shift # Remove from front of line
puts " Now serving: #{current_customer}"
puts " Remaining in line: #{customer_queue}"
end
puts "=" * 60
puts "PART 2: ADVANCED DATA STRUCTURES"
puts "=" * 60
# ==========================================
# 5. TREES - Like Company Organization Chart
# ==========================================
puts "\n5. TREES - Your Company's Organization Chart"
puts "-" * 40
# A tree is like your company's org chart
# CEO at top, managers below, employees under managers
class Employee
attr_accessor :name, :position, :subordinates
def initialize(name, position)
@name = name
@position = position
@subordinates = []
end
def add_subordinate(employee)
@subordinates << employee
end
# Show org chart (tree traversal)
def show_hierarchy(level = 0)
indent = " " * level
puts "#{indent}#{@name} (#{@position})"
@subordinates.each { |sub| sub.show_hierarchy(level + 1) }
end
end
# Building the company tree
ceo = Employee.new("Sarah", "CEO")
sales_manager = Employee.new("John", "Sales Manager")
tech_manager = Employee.new("Mike", "Tech Manager")
# Adding managers under CEO
ceo.add_subordinate(sales_manager)
ceo.add_subordinate(tech_manager)
# Adding employees under managers
sales_manager.add_subordinate(Employee.new("Alice", "Sales Rep"))
sales_manager.add_subordinate(Employee.new("Bob", "Sales Rep"))
tech_manager.add_subordinate(Employee.new("Carol", "Developer"))
tech_manager.add_subordinate(Employee.new("Dave", "Developer"))
puts "Company Organization Chart:"
ceo.show_hierarchy
# ==========================================
# 6. GRAPHS - Like Trading Networks
# ==========================================
puts "\n6. GRAPHS - Your Trading Network"
puts "-" * 40
# A graph is like a trading network where companies
# can trade with multiple other companies (not just hierarchical)
class TradingNetwork
def initialize
@connections = {} # Hash to store trading relationships
end
def add_company(company)
@connections[company] = [] unless @connections[company]
end
def add_trading_relationship(company1, company2)
add_company(company1)
add_company(company2)
@connections[company1] << company2
@connections[company2] << company1 # Bidirectional trading
end
def show_network
puts "Trading Network Connections:"
@connections.each do |company, partners|
puts " #{company} trades with: #{partners.join(', ')}"
end
end
def find_trading_path(start, destination, visited = [])
return [start] if start == destination
return nil if visited.include?(start)
visited << start
@connections[start].each do |partner|
path = find_trading_path(partner, destination, visited.dup)
return [start] + path if path
end
nil
end
end
network = TradingNetwork.new
network.add_trading_relationship("Apple Corp", "Google Inc")
network.add_trading_relationship("Apple Corp", "Microsoft Ltd")
network.add_trading_relationship("Google Inc", "Amazon Co")
network.add_trading_relationship("Microsoft Ltd", "Amazon Co")
network.show_network
# Finding if Apple can reach Amazon through trading partners
path = network.find_trading_path("Apple Corp", "Amazon Co")
puts "\nPath from Apple Corp to Amazon Co: #{path.join(' → ')}"
# ==========================================
# 7. HASHING - Like Employee ID System
# ==========================================
puts "\n7. HASHING - Your Employee ID System"
puts "-" * 40
# Hash tables are like employee badge systems
# Each employee gets a unique ID that quickly finds their info
class EmployeeDatabase
def initialize
@employees = {} # Hash table for O(1) lookup
end
def add_employee(id, name, salary)
@employees[id] = { name: name, salary: salary }
puts "Added employee: #{name} with ID #{id}"
end
def find_employee(id)
employee = @employees[id]
if employee
puts "Found: #{employee[:name]}, Salary: $#{employee[:salary]}"
employee
else
puts "Employee with ID #{id} not found"
nil
end
end
def update_salary(id, new_salary)
if @employees[id]
old_salary = @employees[id][:salary]
@employees[id][:salary] = new_salary
puts "Updated #{@employees[id][:name]}'s salary from $#{old_salary} to $#{new_salary}"
end
end
end
# Using our employee database
hr_system = EmployeeDatabase.new
hr_system.add_employee("EMP001", "Alice Johnson", 65000)
hr_system.add_employee("EMP002", "Bob Smith", 70000)
hr_system.add_employee("EMP003", "Carol Davis", 75000)
puts "\nLooking up employees:"
hr_system.find_employee("EMP002")
hr_system.find_employee("EMP999") # Not found
hr_system.update_salary("EMP001", 68000)
# ==========================================
# 8. HEAPS - Like Priority Customer Service
# ==========================================
puts "\n8. HEAPS - Your VIP Customer Service System"
puts "-" * 40
# A heap is like a VIP customer service system
# Highest priority customers get served first, regardless of arrival time
class VIPCustomerService
def initialize
@customers = [] # Array to represent heap
end
def add_customer(name, priority)
# Add customer with priority (higher number = higher priority)
@customers << { name: name, priority: priority }
bubble_up(@customers.length - 1)
puts "Added #{name} with priority #{priority}"
end
def serve_next_customer
return nil if @customers.empty?
# Serve highest priority customer (root of heap)
customer = @customers[0]
# Move last customer to root and bubble down
@customers[0] = @customers.last
@customers.pop
bubble_down(0) unless @customers.empty?
puts "Now serving: #{customer[:name]} (Priority: #{customer[:priority]})"
customer
end
private
def bubble_up(index)
return if index == 0
parent_index = (index - 1) / 2
if @customers[index][:priority] > @customers[parent_index][:priority]
@customers[index], @customers[parent_index] = @customers[parent_index], @customers[index]
bubble_up(parent_index)
end
end
def bubble_down(index)
left_child = 2 * index + 1
right_child = 2 * index + 2
largest = index
if left_child < @customers.length && @customers[left_child][:priority] > @customers[largest][:priority]
largest = left_child
end
if right_child < @customers.length && @customers[right_child][:priority] > @customers[largest][:priority]
largest = right_child
end
if largest != index
@customers[index], @customers[largest] = @customers[largest], @customers[index]
bubble_down(largest)
end
end
end
vip_service = VIPCustomerService.new
vip_service.add_customer("Regular Customer", 1)
vip_service.add_customer("Gold Member", 5)
vip_service.add_customer("Diamond VIP", 10)
vip_service.add_customer("Silver Member", 3)
puts "\nServing customers by priority:"
4.times { vip_service.serve_next_customer }
puts "=" * 60
puts "PART 3: DYNAMIC PROGRAMMING"
puts "=" * 60
# ==========================================
# 9. DYNAMIC PROGRAMMING - Like Investment Planning
# ==========================================
puts "\n9. DYNAMIC PROGRAMMING - Smart Investment Planning"
puts "-" * 40
# Dynamic Programming is like smart investment planning
# Instead of recalculating the same scenarios repeatedly,
# we remember (memoize) the results of our calculations
class InvestmentPlanner
def initialize
@memo = {} # Our memory bank for calculated results
end
# Classic DP problem: Fibonacci sequence for compound interest
# How much money after n years with compound growth?
def compound_growth(years, growth_rate = 1.1)
# Base cases
return 1000 if years == 0 # Initial investment
return 1100 if years == 1 # After 1 year
# Check if we already calculated this
key = "#{years}_#{growth_rate}"
return @memo[key] if @memo[key]
# Calculate and store result
result = compound_growth(years - 1, growth_rate) * growth_rate
@memo[key] = result
puts "Year #{years}: $#{result.round(2)} (calculated and stored)"
result
end
# Knapsack problem: Maximum profit investment portfolio
def best_investment_portfolio(investments, max_budget)
# investments = [{name: "Stock A", cost: 1000, return: 1200}, ...]
# Create a table to store maximum returns for each budget
dp = Array.new(max_budget + 1, 0)
investments.each_with_index do |investment, i|
cost = investment[:cost]
profit = investment[:return] - investment[:cost]
# Work backwards to avoid using same investment twice
(max_budget).downto(cost) do |budget|
if dp[budget - cost] + profit > dp[budget]
dp[budget] = dp[budget - cost] + profit
puts "With budget $#{budget}, best return is $#{dp[budget]} profit"
end
end
end
dp[max_budget]
end
end
planner = InvestmentPlanner.new
puts "Calculating compound growth over 5 years:"
final_amount = planner.compound_growth(5)
puts "Final amount after 5 years: $#{final_amount.round(2)}"
puts "\nFinding best investment portfolio:"
investments = [
{ name: "Tech Stock", cost: 2000, return: 2800 },
{ name: "Real Estate", cost: 3000, return: 4000 },
{ name: "Bonds", cost: 1000, return: 1300 },
{ name: "Crypto", cost: 1500, return: 2200 }
]
max_profit = planner.best_investment_portfolio(investments, 5000)
puts "Maximum profit with $5000 budget: $#{max_profit}"
puts "=" * 60
puts "PART 4: SORTING & SEARCHING ALGORITHMS"
puts "=" * 60
# ==========================================
# 10. SORTING ALGORITHMS - Like Organizing Sales Data
# ==========================================
puts "\n10. SORTING - Organizing Your Sales Reports"
puts "-" * 40
class SalesAnalyzer
# Bubble Sort - Like organizing papers by repeatedly swapping
def bubble_sort_sales(sales_data)
puts "Bubble Sort: Organizing sales like sorting papers on desk"
data = sales_data.dup
n = data.length
(n - 1).times do |i|
swapped = false
(n - i - 1).times do |j|
if data[j] > data[j + 1]
data[j], data[j + 1] = data[j + 1], data[j]
swapped = true
puts " Swapped: #{data[j + 1]} and #{data[j]} → #{data}"
end
end
break unless swapped
end
data
end
# Quick Sort - Like organizing by dividing into groups
def quick_sort_sales(sales_data)
puts "Quick Sort: Divide sales into groups around a pivot"
return sales_data if sales_data.length <= 1
pivot = sales_data[sales_data.length / 2]
puts " Using pivot: #{pivot}"
left = sales_data.select { |x| x < pivot }
middle = sales_data.select { |x| x == pivot }
right = sales_data.select { |x| x > pivot }
puts " Left (< #{pivot}): #{left}"
puts " Middle (= #{pivot}): #{middle}"
puts " Right (> #{pivot}): #{right}"
quick_sort_sales(left) + middle + quick_sort_sales(right)
end
# Merge Sort - Like merging sorted department reports
def merge_sort_sales(sales_data)
return sales_data if sales_data.length <= 1
mid = sales_data.length / 2
left = merge_sort_sales(sales_data[0...mid])
right = merge_sort_sales(sales_data[mid..-1])
merge(left, right)
end
private
def merge(left, right)
result = []
i = j = 0
# Merge like combining two sorted reports into one
while i < left.length && j < right.length
if left[i] <= right[j]
result << left[i]
i += 1
else
result << right[j]
j += 1
end
end
# Add remaining elements
result + left[i..-1] + right[j..-1]
end
end
# Testing sorting algorithms
monthly_sales = [15000, 8000, 23000, 12000, 31000, 9000, 18000]
analyzer = SalesAnalyzer.new
puts "Original sales data: #{monthly_sales}"
puts "\nBubble Sort Results:"
bubble_result = analyzer.bubble_sort_sales(monthly_sales)
puts "Sorted: #{bubble_result}"
puts "\nQuick Sort Results:"
quick_result = analyzer.quick_sort_sales(monthly_sales)
puts "Sorted: #{quick_result}"
puts "\nMerge Sort Results:"
merge_result = analyzer.merge_sort_sales(monthly_sales)
puts "Sorted: #{merge_result}"
# ==========================================
# 11. SEARCHING ALGORITHMS - Like Finding Customer Records
# ==========================================
puts "\n11. SEARCHING - Finding Customer Records"
puts "-" * 40
class CustomerSearch
def initialize(customer_list)
@customers = customer_list.sort # Binary search needs sorted data
end
# Linear Search - Like looking through files one by one
def linear_search(target)
puts "Linear Search: Checking each customer one by one"
@customers.each_with_index do |customer, index|
puts " Checking position #{index}: #{customer}"
if customer == target
puts " Found #{target} at position #{index}!"
return index
end
end
puts " #{target} not found in customer list"
-1
end
# Binary Search - Like using phone book strategy
def binary_search(target)
puts "Binary Search: Using divide-and-conquer like a phone book"
left = 0
right = @customers.length - 1
while left <= right
mid = (left + right) / 2
puts " Checking middle position #{mid}: #{@customers[mid]}"
if @customers[mid] == target
puts " Found #{target} at position #{mid}!"
return mid
elsif @customers[mid] < target
puts " #{target} is larger, searching right half"
left = mid + 1
else
puts " #{target} is smaller, searching left half"
right = mid - 1
end
end
puts " #{target} not found in customer list"
-1
end
end
# Testing search algorithms
customer_names = ["Alice Corp", "Beta Industries", "Charlie Ltd", "Delta Inc",
"Echo Systems", "Foxtrot Co", "Golf Enterprises"]
searcher = CustomerSearch.new(customer_names)
puts "Customer database: #{searcher.instance_variable_get(:@customers)}"
puts "\nSearching for 'Delta Inc':"
searcher.linear_search("Delta Inc")
puts "\nBinary search for 'Delta Inc':"
searcher.binary_search("Delta Inc")
puts "=" * 60
puts "PART 5: COMPLEXITY ANALYSIS (BIG O)"
puts "=" * 60
# ==========================================
# 12. BIG O NOTATION - Like Business Efficiency Analysis
# ==========================================
puts "\n12. BIG O - Measuring Business Process Efficiency"
puts "-" * 40
class EfficiencyAnalyzer
# O(1) - Constant Time: Like accessing employee by ID badge
def constant_time_example(employee_database, employee_id)
puts "O(1) - Constant Time: Direct employee lookup by ID"
puts " No matter if we have 10 or 10,000 employees,"
puts " finding by ID always takes the same time"
start_time = Time.now
employee = employee_database[employee_id]
end_time = Time.now
puts " Found employee in #{(end_time - start_time) * 1000} milliseconds"
employee
end
# O(n) - Linear Time: Like counting all inventory items
def linear_time_example(inventory_list)
puts "O(n) - Linear Time: Counting total inventory value"
puts " Time grows proportionally with inventory size"
start_time = Time.now
total_value = 0
inventory_list.each_with_index do |item, index|
total_value += item[:value]
puts " Item #{index + 1}: $#{item[:value]} (Running total: $#{total_value})"
end
end_time = Time.now
puts " Processed #{inventory_list.length} items in #{(end_time - start_time) * 1000} milliseconds"
total_value
end
# O(n²) - Quadratic Time: Like comparing every employee with every other
def quadratic_time_example(employee_salaries)
puts "O(n²) - Quadratic Time: Finding all salary comparison pairs"
puts " Time grows exponentially - very slow for large datasets!"
start_time = Time.now
comparisons = 0
employee_salaries.each_with_index do |salary1, i|
employee_salaries.each_with_index do |salary2, j|
next if i >= j # Avoid duplicate comparisons
comparisons += 1
if salary1 > salary2
puts " Employee #{i} ($#{salary1}) earns more than Employee #{j} ($#{salary2})"
end
end
end
end_time = Time.now
puts " Made #{comparisons} comparisons in #{(end_time - start_time) * 1000} milliseconds"
puts " With #{employee_salaries.length} employees, we needed #{comparisons} comparisons"
puts " Formula: n(n-1)/2 where n = #{employee_salaries.length}"
end
# O(log n) - Logarithmic Time: Like binary search in sorted customer list
def logarithmic_time_example(sorted_customers, target)
puts "O(log n) - Logarithmic Time: Binary search efficiency"
puts " Even with millions of customers, only needs ~20 steps!"
start_time = Time.now
steps = 0
left, right = 0, sorted_customers.length - 1
while left <= right
steps += 1
mid = (left + right) / 2
puts " Step #{steps}: Checking position #{mid} (#{sorted_customers[mid]})"
if sorted_customers[mid] == target
end_time = Time.now
puts " Found #{target} in #{steps} steps!"
puts " Time taken: #{(end_time - start_time) * 1000} milliseconds"
return mid
elsif sorted_customers[mid] < target
left = mid + 1
else
right = mid - 1
end
end
end_time = Time.now
puts " #{target} not found after #{steps} steps"
puts " Time taken: #{(end_time - start_time) * 1000} milliseconds"
-1
end
def complexity_comparison
puts "\nBusiness Efficiency Comparison (Big O Notation):"
puts " O(1) - Constant: Employee badge lookup - BEST"
puts " Like having a direct phone number"
puts " O(log n) - Logarithmic: Binary search - EXCELLENT"
puts " Like using a phone book efficiently"
puts " O(n) - Linear: Counting inventory - GOOD"
puts " Time increases proportionally with size"
puts " O(n log n) - Linearithmic: Good sorting algorithms - ACCEPTABLE"
puts " Like organizing files efficiently"
puts " O(n²) - Quadratic: Comparing all pairs - POOR"
puts " Like comparing every employee with every other"
puts " O(2ⁿ) - Exponential: Trying all combinations - TERRIBLE"
puts " Like trying every possible password"
puts "\nReal business impact:"
[10, 100, 1000, 10000].each do |n|
puts " With #{n} records:"
puts " O(1): 1 operation"
puts " O(log n): #{Math.log2(n).ceil} operations"
puts " O(n): #{n} operations"
puts " O(n²): #{n * n} operations"
end
end
end
# Testing efficiency analysis
analyzer = EfficiencyAnalyzer.new
# O(1) example
employee_db = {
"EMP001" => { name: "Alice", salary: 65000 },
"EMP002" => { name: "Bob", salary: 70000 },
"EMP003" => { name: "Carol", salary: 75000 }
}
analyzer.constant_time_example(employee_db, "EMP002")
puts "\n" + "-" * 40
# O(n) example
inventory = [
{ item: "Laptops", value: 50000 },
{ item: "Phones", value: 30000 },
{ item: "Tablets", value: 20000 },
{ item: "Monitors", value: 15000 }
]
analyzer.linear_time_example(inventory)
puts "\n" + "-" * 40
# O(n²) example
salaries = [65000, 70000, 55000, 80000, 60000]
analyzer.quadratic_time_example(salaries)
puts "\n" + "-" * 40
# O(log n) example
customers = ["Alpha Corp", "Beta Inc", "Delta Ltd", "Echo Co", "Foxtrot Inc", "Golf Corp"]
analyzer.logarithmic_time_example(customers, "Delta Ltd")
puts "\n" + "-" * 40
analyzer.complexity_comparison
puts "\n" + "=" * 60
puts "SUMMARY: Key Business Takeaways"
puts "=" * 60
puts "\n🎯 PRACTICAL APPLICATIONS:"
puts " • Arrays: Employee records, product catalogs"
puts " • Linked Lists: Supply chains, process workflows"
puts " • Stacks: Undo operations, function calls"
puts " • Queues: Customer service, task processing"
puts " • Trees: Organization charts, decision trees"
puts " • Graphs: Trading networks, social connections"
puts " • Hash Tables: Fast lookups (employee IDs, product codes)"
puts " • Heaps: Priority queues (VIP customers, urgent tasks)"
puts " • Dynamic Programming: Optimization problems, planning"
puts " • Sorting: Organizing data for analysis"
puts " • Searching: Finding specific records quickly"
puts " • Big O: Measuring efficiency and scalability"
puts "\n💡 BUSINESS WISDOM:"
puts " Choose the right data structure for your business needs!"
puts " Consider scalability - will it work with 1M customers?"
puts " Efficiency matters - O(n²) algorithms can kill performance!"
puts " Sometimes simple solutions (arrays) are perfect"
puts " Complex problems often need clever solutions (dynamic programming)"
puts "\n🚀 Remember: Good algorithms are like good business processes"
puts " - They scale efficiently"
puts " - They're reliable and predictable"
puts " - They solve real problems elegantly"
# Ruby OOP Fundamentals for Business People
# Think of OOP like building a company structure
puts "=" * 60
puts "RUBY OOP FUNDAMENTALS - BUILDING YOUR BUSINESS"
puts "=" * 60
# ==========================================
# 1. CLASSES - Your Business Blueprint
# ==========================================
puts "\n1. CLASSES - The Blueprint for Your Business"
puts "-" * 50
# A class is like a business plan template
# It defines what every business of this type should have and do
# But it's not a real business until you create an instance of it
class Restaurant
# These are like the standard features every restaurant must have
# Think of them as the "company policies" that define what makes a restaurant
def initialize(name, cuisine_type)
# This is like the "grand opening" method
# Every time you create a new restaurant, this runs first
@name = name # @ means this belongs to THIS specific restaurant
@cuisine_type = cuisine_type # Each restaurant instance gets its own copy
@is_open = false # All restaurants start closed
@daily_revenue = 0 # Start with no money
puts "🏪 Opening new restaurant: #{@name} (#{@cuisine_type} cuisine)"
end
# These are the actions every restaurant can perform
# Think of them as "standard operating procedures"
def open_for_business
@is_open = true
puts "🔓 #{@name} is now OPEN for business!"
end
def close_for_day
@is_open = false
puts "🔒 #{@name} is now CLOSED. Today's revenue: $#{@daily_revenue}"
@daily_revenue = 0 # Reset for tomorrow
end
def serve_customer(order_value)
if @is_open
@daily_revenue += order_value
puts "💰 Served customer at #{@name}. Order: $#{order_value} (Total today: $#{@daily_revenue})"
else
puts "❌ Sorry, #{@name} is closed!"
end
end
# This lets other people ask about the restaurant's status
# Think of it as "public information" that anyone can request
def status_report
status = @is_open ? "OPEN" : "CLOSED"
puts "📊 #{@name} Status: #{status}, Cuisine: #{@cuisine_type}, Today's Revenue: $#{@daily_revenue}"
end
end
# Creating actual restaurants from our blueprint
# This is like actually starting real businesses using your business plan
puts "\nCreating restaurants from our blueprint:"
pizza_place = Restaurant.new("Mario's Pizza", "Italian")
sushi_bar = Restaurant.new("Tokyo Express", "Japanese")
burger_joint = Restaurant.new("Burger Heaven", "American")
# Each restaurant is independent - they don't share money or status
puts "\nOperating our restaurants:"
pizza_place.open_for_business
pizza_place.serve_customer(25.50)
pizza_place.serve_customer(18.75)
sushi_bar.open_for_business
sushi_bar.serve_customer(45.00)
# Burger joint stays closed today
burger_joint.serve_customer(12.00) # This should fail
puts "\nEnd of day status reports:"
pizza_place.status_report
sushi_bar.status_report
burger_joint.status_report
# ==========================================
# 2. INHERITANCE - Business Expansion Models
# ==========================================
puts "\n\n2. INHERITANCE - Expanding Your Business Model"
puts "-" * 50
# Inheritance is like creating specialized versions of your business
# A FastFoodRestaurant IS A Restaurant, but with extra features
class FastFoodRestaurant < Restaurant # < means "inherits from"
# This gets EVERYTHING from Restaurant class, plus we can add more
def initialize(name, cuisine_type, drive_thru = false)
# Call the parent's initialization first (like following the basic business plan)
super(name, cuisine_type) # This runs Restaurant's initialize method
# Then add our special fast-food features
@has_drive_thru = drive_thru
@orders_per_hour = 0
puts "🚗 #{name} is a fast-food restaurant with drive-thru: #{drive_thru}"
end
# Override the parent's method with our faster version
def serve_customer(order_value)
if @is_open
@daily_revenue += order_value
@orders_per_hour += 1
puts "⚡ FAST service at #{@name}! Order: $#{order_value} (#{@orders_per_hour} orders this hour)"
else
puts "❌ Sorry, #{@name} is closed!"
end
end
# Add completely new methods that only fast-food places have
def serve_drive_thru(order_value)
if @has_drive_thru && @is_open
@daily_revenue += order_value
@orders_per_hour += 2 # Drive-thru is even faster!
puts "🚗💨 Drive-thru service at #{@name}! Order: $#{order_value}"
elsif !@has_drive_thru
puts "❌ #{@name} doesn't have a drive-thru!"
else
puts "❌ Sorry, #{@name} is closed!"
end
end
def hourly_efficiency_report
puts "📈 #{@name} served #{@orders_per_hour} customers this hour"
@orders_per_hour = 0 # Reset for next hour
end
end
puts "\nCreating specialized fast-food restaurants:"
mcburgers = FastFoodRestaurant.new("McBurgers", "American", true) # With drive-thru
quick_pizza = FastFoodRestaurant.new("Quick Pizza", "Italian", false) # No drive-thru
puts "\nTesting inheritance and new features:"
mcburgers.open_for_business # This method came from Restaurant class
mcburgers.serve_customer(8.99) # This is our overridden faster version
mcburgers.serve_drive_thru(12.50) # This is completely new
mcburgers.hourly_efficiency_report # This is also new
quick_pizza.open_for_business
quick_pizza.serve_customer(15.99)
quick_pizza.serve_drive_thru(10.00) # This should fail - no drive-thru!
# ==========================================
# 3. MODULES - Shared Business Capabilities
# ==========================================
puts "\n\n3. MODULES - Shared Business Capabilities"
puts "-" * 50
# Modules are like business certifications or capabilities
# that different types of businesses can share
# Think of them as "business add-ons" that you can mix into any company
module DeliveryService
# This module contains everything needed to offer delivery
# Any business can "include" this to gain delivery capabilities
def add_delivery_option
@delivery_available = true
@delivery_fee = 3.99
puts "🚚 #{@name} now offers delivery service! Fee: $#{@delivery_fee}"
end
def deliver_order(order_value, distance)
if @delivery_available && @is_open
# Calculate delivery fee based on distance
total_fee = @delivery_fee + (distance * 0.50)
total_order = order_value + total_fee
@daily_revenue += total_order
puts "🏠 Delivering to customer! Order: $#{order_value}, Delivery: $#{total_fee.round(2)}"
puts " Total charged: $#{total_order.round(2)}"
elsif !@delivery_available
puts "❌ #{@name} doesn't offer delivery!"
else
puts "❌ Sorry, #{@name} is closed!"
end
end
end
module LoyaltyProgram
# This module handles customer loyalty points
# Any business can add this to reward repeat customers
def setup_loyalty_program(points_per_dollar = 1)
@loyalty_program = true
@points_rate = points_per_dollar
@customer_points = {} # Hash to store each customer's points
puts "⭐ #{@name} launched loyalty program! Earn #{@points_rate} point per $1 spent"
end
def serve_loyalty_customer(customer_name, order_value)
if @is_open
@daily_revenue += order_value
if @loyalty_program
# Add points for this purchase
points_earned = (order_value * @points_rate).to_i
@customer_points[customer_name] ||= 0
@customer_points[customer_name] += points_earned
puts "💎 #{customer_name} earned #{points_earned} points! Total: #{@customer_points[customer_name]}"
end
else
puts "❌ Sorry, #{@name} is closed!"
end
end
def redeem_points(customer_name, points_to_use)
return unless @loyalty_program && @customer_points[customer_name]
if @customer_points[customer_name] >= points_to_use
discount = points_to_use * 0.01 # 1 point = 1 cent
@customer_points[customer_name] -= points_to_use
puts "🎁 #{customer_name} redeemed #{points_to_use} points for $#{discount} discount!"
return discount
else
puts "❌ #{customer_name} doesn't have enough points!"
return 0
end
end
end
# Now let's create restaurants that use these modules
# This is called "mixing in" the modules
class ModernRestaurant < Restaurant
include DeliveryService # Mix in delivery capabilities
include LoyaltyProgram # Mix in loyalty program capabilities
# Now this class has ALL methods from:
# 1. Restaurant (parent class)
# 2. DeliveryService (mixed-in module)
# 3. LoyaltyProgram (mixed-in module)
# Plus any methods we define here
def initialize(name, cuisine_type)
super(name, cuisine_type) # Call parent's initialize
puts "🆕 #{@name} is a modern restaurant with advanced features!"
end
end
puts "\nCreating modern restaurants with mixed-in capabilities:"
tech_cafe = ModernRestaurant.new("Tech Cafe", "Fusion")
tech_cafe.open_for_business
# Using inherited methods from Restaurant
tech_cafe.serve_customer(22.50)
# Using methods from DeliveryService module
tech_cafe.add_delivery_option
tech_cafe.deliver_order(18.75, 2.5) # $18.75 order, 2.5 miles away
# Using methods from LoyaltyProgram module
tech_cafe.setup_loyalty_program(2) # 2 points per dollar
tech_cafe.serve_loyalty_customer("Alice", 25.00)
tech_cafe.serve_loyalty_customer("Alice", 15.00)
tech_cafe.redeem_points("Alice", 50)
# ==========================================
# 4. RUBY'S OBJECT MODEL - The Business Hierarchy
# ==========================================
puts "\n\n4. RUBY'S OBJECT MODEL - Understanding the Business Hierarchy"
puts "-" * 50
# Ruby's object model is like understanding the corporate structure
# Every object knows its place in the hierarchy
puts "Understanding object relationships:"
# Every object has a class (its direct blueprint)
puts "tech_cafe's class: #{tech_cafe.class}"
puts "tech_cafe is a ModernRestaurant?: #{tech_cafe.is_a?(ModernRestaurant)}"
puts "tech_cafe is a Restaurant?: #{tech_cafe.is_a?(Restaurant)}" # true because of inheritance
puts "tech_cafe is an Object?: #{tech_cafe.is_a?(Object)}" # true - everything inherits from Object
# Classes also have classes (they're objects too!)
puts "\nClasses are objects too:"
puts "ModernRestaurant's class: #{ModernRestaurant.class}"
puts "Restaurant's class: #{Restaurant.class}"
# Method lookup chain - how Ruby finds methods
puts "\nMethod lookup chain for tech_cafe:"
puts tech_cafe.class.ancestors
# This shows the order Ruby searches for methods:
# 1. ModernRestaurant
# 2. LoyaltyProgram (mixed-in module)
# 3. DeliveryService (mixed-in module)
# 4. Restaurant (parent class)
# 5. Object (ultimate parent)
# 6. Kernel (basic Ruby methods)
# 7. BasicObject (absolute base)
puts "\nDemonstrating method lookup:"
puts "When we call tech_cafe.serve_customer(10):"
puts " 1. Ruby looks in ModernRestaurant class - not found"
puts " 2. Ruby looks in LoyaltyProgram module - not found"
puts " 3. Ruby looks in DeliveryService module - not found"
puts " 4. Ruby looks in Restaurant class - FOUND! Uses that method"
# ==========================================
# 5. PRACTICAL BUSINESS EXAMPLE
# ==========================================
puts "\n\n5. PUTTING IT ALL TOGETHER - Restaurant Chain Management"
puts "-" * 50
# Let's create a comprehensive restaurant chain system
# that demonstrates all OOP concepts working together
module Reporting
def generate_monthly_report
puts "\n📋 MONTHLY REPORT for #{@name}"
puts " Type: #{self.class}"
puts " Status: #{@is_open ? 'Currently Open' : 'Currently Closed'}"
puts " Special Features:"
# Check what capabilities this restaurant has
puts " - Delivery: #{respond_to?(:deliver_order) ? 'Yes' : 'No'}"
puts " - Loyalty Program: #{respond_to?(:setup_loyalty_program) ? 'Yes' : 'No'}"
puts " - Drive-thru: #{instance_variable_defined?(:@has_drive_thru) ? @has_drive_thru : 'No'}"
puts " Today's Revenue: $#{@daily_revenue}"
end
end
class RestaurantChain
def initialize(chain_name)
@chain_name = chain_name
@locations = []
puts "🏢 Created restaurant chain: #{@chain_name}"
end
def add_location(restaurant)
# Add reporting capability to any restaurant we manage
restaurant.extend(Reporting) # extend adds module methods to a single object
@locations << restaurant
puts "➕ Added #{restaurant.instance_variable_get(:@name)} to #{@chain_name} chain"
end
def chain_status_report
puts "\n🏢 #{@chain_name} CHAIN STATUS REPORT"
puts "=" * 40
@locations.each { |location| location.generate_monthly_report }
end
end
# Creating a restaurant chain with different types of restaurants
puts "\nBuilding a restaurant chain empire:"
chain = RestaurantChain.new("Delicious Foods Inc")
# Add different types of restaurants to our chain
location1 = Restaurant.new("Downtown Bistro", "French")
location2 = FastFoodRestaurant.new("Speedy Burgers", "American", true)
location3 = ModernRestaurant.new("Tech Diner", "Fusion")
# Configure the modern restaurant
location3.add_delivery_option
location3.setup_loyalty_program
# Add all locations to chain
chain.add_location(location1)
chain.add_location(location2)
chain.add_location(location3)
# Simulate some business activity
location1.open_for_business
location1.serve_customer(45.00)
location2.open_for_business
location2.serve_customer(12.99)
location2.serve_drive_thru(8.50)
location3.open_for_business
location3.serve_customer(28.75)
location3.deliver_order(22.00, 1.8)
# Generate comprehensive chain report
chain.chain_status_report
puts "\n" + "=" * 60
puts "KEY OOP CONCEPTS SUMMARY"
puts "=" * 60
puts "\n🏗️ CLASSES are blueprints (like business plans)"
puts " - They define what attributes and behaviors objects will have"
puts " - You create instances (actual businesses) from these blueprints"
puts "\n🧬 INHERITANCE lets you create specialized versions"
puts " - FastFoodRestaurant inherits from Restaurant"
puts " - Gets all parent features plus can add/modify behavior"
puts "\n🧩 MODULES are reusable capabilities you can mix in"
puts " - DeliveryService can be added to any restaurant type"
puts " - Use 'include' to mix into class, 'extend' to add to single object"
puts "\n🌳 OBJECT MODEL shows the hierarchy"
puts " - Every object knows its class and inheritance chain"
puts " - Ruby searches up the chain to find methods"
puts " - Everything ultimately inherits from Object"
puts "\n💡 BUSINESS LESSON:"
puts " OOP lets you model real business relationships in code"
puts " - Inheritance = 'is-a' relationships (FastFood IS A Restaurant)"
puts " - Modules = 'can-do' capabilities (Restaurant CAN DO delivery)"
puts " - This makes code organized, reusable, and maintainable"
# Ruby Blocks, Procs & Lambdas for Business People
# Think of these as different ways to package business procedures
puts "=" * 60
puts "RUBY BLOCKS, PROCS & LAMBDAS - BUSINESS PROCEDURES"
puts "=" * 60
# ==========================================
# 1. BLOCKS - Your Standard Operating Procedures
# ==========================================
puts "\n1. BLOCKS - Standard Operating Procedures (SOPs)"
puts "-" * 50
# A block is like a standard procedure that you can pass to different methods
# Think of it as a "how-to" instruction that can be used in various situations
# Blocks are written with { } for one line or do...end for multiple lines
puts "Understanding blocks through business processes:\n"
# Example 1: Processing employee list with different procedures
employees = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
puts "Our employee list: #{employees}"
# Block example 1: Simple procedure passed to each method
puts "\nSending welcome emails (using a block):"
employees.each { |employee| puts "📧 Sending welcome email to #{employee}" }
# Block example 2: Multi-line procedure with do...end
puts "\nProcessing payroll (using a block with multiple steps):"
employees.each do |employee|
puts "💰 Processing payroll for #{employee}"
puts " - Calculating hours worked"
puts " - Computing tax deductions"
puts " - Generating pay stub"
puts " - Sending direct deposit"
end
# Example 2: Blocks with business logic
sales_data = [1200, 800, 1500, 900, 2000, 750, 1800]
puts "\nOriginal sales data: #{sales_data}"
# Using select with a block to filter data (like finding high performers)
high_sales = sales_data.select { |amount| amount > 1000 }
puts "High sales (>$1000): #{high_sales}"
# Using map with a block to transform data (like applying commission)
commission_rates = sales_data.map { |amount| amount * 0.05 } # 5% commission
puts "Commission earned: #{commission_rates}"
# Using reduce with a block to accumulate data (like total revenue)
total_revenue = sales_data.reduce(0) { |total, amount| total + amount }
puts "Total revenue: $#{total_revenue}"
# Example 3: Creating your own methods that accept blocks
class BusinessReport
def initialize(company_name)
@company_name = company_name
end
# This method accepts a block and yields control to it
def generate_report(data)
puts "\n📊 #{@company_name} Business Report"
puts "=" * 30
# yield passes control to the block that was given to this method
# Think of it as "now execute the custom procedure the caller provided"
yield(data) if block_given? # Only run block if one was provided
puts "=" * 30
puts "Report completed ✅"
end
# Method with multiple yield points (like a procedure with multiple steps)
def quarterly_review(departments)
puts "\n🔍 Quarterly Review Process Started"
departments.each do |dept|
puts "\nReviewing #{dept} department:"
yield(dept, "performance") if block_given? # First yield - performance review
yield(dept, "budget") if block_given? # Second yield - budget review
end
puts "\n✅ Quarterly review completed"
end
end
# Using our custom methods with blocks
report_generator = BusinessReport.new("Tech Innovations Inc")
# Pass a block that defines how to process the data
report_generator.generate_report(sales_data) do |data|
puts "Sales Summary:"
puts " Total Sales: $#{data.sum}"
puts " Average Sale: $#{data.sum / data.length}"
puts " Best Month: $#{data.max}"
puts " Worst Month: $#{data.min}"
end
# Using the quarterly review with a block that handles both performance and budget
departments = ["Sales", "Marketing", "Engineering"]
report_generator.quarterly_review(departments) do |dept, review_type|
case review_type
when "performance"
puts " 📈 #{dept} performance: Exceeds expectations"
when "budget"
puts " 💰 #{dept} budget utilization: 85% used"
end
end
# ==========================================
# 2. PROCS - Reusable Business Procedures
# ==========================================
puts "\n\n2. PROCS - Reusable Business Procedures"
puts "-" * 50
# A Proc is like a business procedure that you can save and reuse
# Think of it as writing down a standard procedure once, then using it many times
# Unlike blocks, Procs are objects that can be stored in variables
puts "Creating reusable business procedures with Procs:\n"
# Creating a Proc - like writing down a standard procedure
customer_welcome_procedure = Proc.new do |customer_name, account_type|
puts "🤝 Welcome #{customer_name}!"
puts " Account type: #{account_type}"
puts " Setting up your dashboard..."
puts " Sending account confirmation email..."
puts " Assignment to customer success manager: pending"
end
# Using the Proc - like following the written procedure
puts "Welcoming new customers using our standard procedure:"
customer_welcome_procedure.call("Alice Johnson", "Premium")
customer_welcome_procedure.call("Bob Smith", "Standard")
# You can also use .() as shorthand for .call()
customer_welcome_procedure.("Charlie Brown", "Enterprise")
# Example: Creating different business calculation procedures
puts "\nBusiness calculation procedures:"
# Tax calculation procedure
tax_calculator = Proc.new { |amount| amount * 0.08 } # 8% tax
# Discount calculation procedure
discount_calculator = Proc.new do |amount, customer_tier|
case customer_tier
when "bronze" then amount * 0.05 # 5% discount
when "silver" then amount * 0.10 # 10% discount
when "gold" then amount * 0.15 # 15% discount
else 0 # No discount
end
end
# Commission calculation procedure
commission_calculator = Proc.new { |sale_amount| sale_amount * 0.07 } # 7% commission
# Using these procedures in business operations
order_amount = 1000
customer_tier = "silver"
tax = tax_calculator.call(order_amount)
discount = discount_calculator.call(order_amount, customer_tier)
commission = commission_calculator.call(order_amount)
puts "Order processing:"
puts " Order amount: $#{order_amount}"
puts " Customer tier: #{customer_tier}"
puts " Tax: $#{tax}"
puts " Discount: $#{discount}"
puts " Sales commission: $#{commission}"
puts " Final total: $#{order_amount + tax - discount}"
# Example: Passing Procs to methods (like assigning procedures to different processes)
class OrderProcessor
def process_orders(orders, tax_proc, discount_proc)
puts "\n🏭 Processing orders with custom procedures:"
orders.each do |order|
customer = order[:customer]
amount = order[:amount]
tier = order[:tier]
tax = tax_proc.call(amount)
discount = discount_proc.call(amount, tier)
final_total = amount + tax - discount
puts " #{customer}: $#{amount} → Final: $#{final_total.round(2)} (tax: $#{tax}, discount: $#{discount})"
end
end
end
# Sample orders
orders = [
{ customer: "Alice Corp", amount: 5000, tier: "gold" },
{ customer: "Bob Industries", amount: 2000, tier: "silver" },
{ customer: "Charlie LLC", amount: 1000, tier: "bronze" }
]
processor = OrderProcessor.new
processor.process_orders(orders, tax_calculator, discount_calculator)
# ==========================================
# 3. LAMBDAS - Strict Business Procedures
# ==========================================
puts "\n\n3. LAMBDAS - Strict Business Procedures"
puts "-" * 50
# A lambda is like a Proc, but with stricter rules
# Think of it as a formal business procedure with exact requirements
# Lambdas check the number of arguments and handle returns differently
puts "Creating strict business procedures with lambdas:\n"
# Creating a lambda - notice the -> syntax (stabby lambda)
strict_discount_calculator = lambda do |amount, tier, years_customer|
base_discount = case tier
when "bronze" then 0.05
when "silver" then 0.10
when "gold" then 0.15
else 0.0
end
# Loyalty bonus based on years as customer
loyalty_bonus = years_customer * 0.01 # 1% per year
total_discount_rate = base_discount + loyalty_bonus
# Cap the discount at 25%
total_discount_rate = [total_discount_rate, 0.25].min
discount = amount * total_discount_rate
puts " Discount calculation: #{tier} (#{base_discount*100}%) + loyalty (#{loyalty_bonus*100}%) = #{total_discount_rate*100}%"
discount
end
# Alternative syntax for simple lambdas
simple_tax_calc = ->(amount) { amount * 0.08 }
# Demonstrating lambda strictness
puts "Lambda strictness demonstration:"
begin
# This works - correct number of arguments
discount = strict_discount_calculator.call(1000, "silver", 3)
puts "✅ Correct args: Discount = $#{discount.round(2)}"
rescue ArgumentError => e
puts "❌ Error: #{e.message}"
end
begin
# This fails - wrong number of arguments (lambdas are strict!)
discount = strict_discount_calculator.call(1000, "silver") # Missing years_customer
puts "Discount = $#{discount}"
rescue ArgumentError => e
puts "❌ Lambda error: #{e.message}"
end
# Compare with Proc - Procs are more forgiving
lenient_proc = Proc.new { |amount, tier, years| puts "Proc got: #{amount}, #{tier}, #{years}" }
puts "\nComparing Proc vs Lambda argument handling:"
puts "Proc with missing arguments:"
lenient_proc.call(1000, "gold") # Works - missing args become nil
puts "Lambda with missing arguments:"
begin
strict_discount_calculator.call(1000, "gold") # Fails - strict about arguments
rescue ArgumentError => e
puts "❌ #{e.message}"
end
# ==========================================
# 4. PRACTICAL BUSINESS APPLICATIONS
# ==========================================
puts "\n\n4. PRACTICAL BUSINESS APPLICATIONS"
puts "-" * 50
# Real-world business scenario: E-commerce order processing system
class EcommerceSystem
def initialize
@payment_processors = {}
@shipping_calculators = {}
@notification_handlers = {}
end
# Register different business procedures for different operations
def register_payment_processor(name, processor_proc)
@payment_processors[name] = processor_proc
puts "💳 Registered payment processor: #{name}"
end
def register_shipping_calculator(name, calculator_lambda)
@shipping_calculators[name] = calculator_lambda
puts "🚚 Registered shipping calculator: #{name}"
end
def register_notification_handler(notification_type, &handler_block)
# &handler_block converts a block to a Proc
@notification_handlers[notification_type] = handler_block
puts "📧 Registered notification handler: #{notification_type}"
end
def process_order(order_details)
puts "\n🛒 Processing order ##{order_details[:id]}"
# Use the appropriate payment processor
payment_method = order_details[:payment_method]
if processor = @payment_processors[payment_method]
processor.call(order_details[:amount], order_details[:customer])
end
# Calculate shipping using the appropriate method
shipping_method = order_details[:shipping_method]
if calculator = @shipping_calculators[shipping_method]
shipping_cost = calculator.call(order_details[:weight], order_details[:distance])
puts "📦 Shipping cost: $#{shipping_cost}"
end
# Send appropriate notifications
if handler = @notification_handlers[:order_confirmation]
handler.call(order_details[:customer], order_details[:id])
end
puts "✅ Order ##{order_details[:id]} processed successfully"
end
end
# Setting up the e-commerce system with different procedures
ecommerce = EcommerceSystem.new
# Register payment processors (using Procs)
credit_card_processor = Proc.new do |amount, customer|
puts "💳 Processing credit card payment of $#{amount} for #{customer}"
puts " - Validating card details"
puts " - Charging card"
puts " - Sending receipt"
end
paypal_processor = Proc.new do |amount, customer|
puts "🏦 Processing PayPal payment of $#{amount} for #{customer}"
puts " - Redirecting to PayPal"
puts " - Confirming payment"
puts " - Returning to store"
end
ecommerce.register_payment_processor("credit_card", credit_card_processor)
ecommerce.register_payment_processor("paypal", paypal_processor)
# Register shipping calculators (using lambdas for strict argument checking)
standard_shipping = lambda do |weight, distance|
base_cost = 5.99
weight_cost = weight * 0.50 # $0.50 per pound
distance_cost = distance * 0.10 # $0.10 per mile
base_cost + weight_cost + distance_cost
end
express_shipping = lambda do |weight, distance|
base_cost = 15.99
weight_cost = weight * 0.75 # Higher rate for express
distance_cost = distance * 0.15
base_cost + weight_cost + distance_cost
end
ecommerce.register_shipping_calculator("standard", standard_shipping)
ecommerce.register_shipping_calculator("express", express_shipping)
# Register notification handlers (using blocks)
ecommerce.register_notification_handler(:order_confirmation) do |customer, order_id|
puts "📧 Sending order confirmation to #{customer}"
puts " Order ##{order_id} has been received and is being processed"
puts " You will receive shipping updates soon"
end
# Process some sample orders
sample_orders = [
{
id: "ORD001",
customer: "Alice Johnson",
amount: 99.99,
payment_method: "credit_card",
shipping_method: "standard",
weight: 2.5,
distance: 25
},
{
id: "ORD002",
customer: "Bob Smith",
amount: 149.99,
payment_method: "paypal",
shipping_method: "express",
weight: 1.2,
distance: 15
}
]
sample_orders.each { |order| ecommerce.process_order(order) }
# ==========================================
# 5. WHEN TO USE WHICH: BUSINESS DECISION GUIDE
# ==========================================
puts "\n\n5. WHEN TO USE WHICH: BUSINESS DECISION GUIDE"
puts "-" * 50
puts "\n📋 BLOCKS - Use for immediate, one-time procedures:"
puts " ✅ Processing a list of items with custom logic"
puts " ✅ Configuring behavior in a method call"
puts " ✅ Event handling (like 'when this happens, do that')"
puts " ✅ Quick transformations and filters"
# Example: Quick data processing
monthly_revenues = [45000, 52000, 48000, 61000, 55000, 59000]
puts "\nBlock example - Quick revenue analysis:"
quarterly_avg = monthly_revenues.each_slice(3).map do |quarter|
quarter.sum / quarter.length
end
puts "Quarterly averages: #{quarterly_avg}"
puts "\n📦 PROCS - Use for reusable business procedures:"
puts " ✅ Standard calculations used in multiple places"
puts " ✅ Business rules that might change"
puts " ✅ Configurable behavior (like plugins)"
puts " ✅ When you need to store the procedure for later"
# Example: Configurable business rules
regional_tax_rates = {
"CA" => Proc.new { |amount| amount * 0.0875 }, # California: 8.75%
"NY" => Proc.new { |amount| amount * 0.08 }, # New York: 8%
"TX" => Proc.new { |amount| amount * 0.0625 }, # Texas: 6.25%
"FL" => Proc.new { |amount| 0 } # Florida: 0% (no state tax)
}
puts "\nProc example - Regional tax calculation:"
order_amount = 1000
["CA", "NY", "TX", "FL"].each do |state|
tax = regional_tax_rates[state].call(order_amount)
puts " #{state}: $#{order_amount} order → $#{tax} tax"
end
puts "\n🎯 LAMBDAS - Use for strict, formal procedures:"
puts " ✅ Critical calculations that must have exact inputs"
puts " ✅ APIs and interfaces with strict contracts"
puts " ✅ Mathematical formulas and financial calculations"
puts " ✅ When argument count validation is important"
# Example: Formal financial calculations
compound_interest_calculator = lambda do |principal, rate, time, compounds_per_year|
# Formula: A = P(1 + r/n)^(nt)
# This MUST have exactly 4 arguments - no exceptions!
rate_per_period = rate / compounds_per_year
total_periods = compounds_per_year * time
final_amount = principal * ((1 + rate_per_period) ** total_periods)
{
principal: principal,
final_amount: final_amount.round(2),
interest_earned: (final_amount - principal).round(2)
}
end
puts "\nLambda example - Compound interest calculation:"
investment_result = compound_interest_calculator.call(10000, 0.05, 10, 12)
puts " Investment: $#{investment_result[:principal]}"
puts " After 10 years: $#{investment_result[:final_amount]}"
puts " Interest earned: $#{investment_result[:interest_earned]}"
# ==========================================
# 6. ADVANCED BUSINESS PATTERNS
# ==========================================
puts "\n\n6. ADVANCED BUSINESS PATTERNS"
puts "-" * 50
# Pattern 1: Strategy Pattern - Different business strategies
class MarketingCampaign
def initialize(name)
@name = name
@strategies = {}
end
def add_strategy(channel, strategy_proc)
@strategies[channel] = strategy_proc
puts "📢 Added #{channel} strategy to #{@name} campaign"
end
def execute_campaign(budget_per_channel)
puts "\n🚀 Executing #{@name} campaign:"
@strategies.each do |channel, strategy|
budget = budget_per_channel[channel] || 0
if budget > 0
puts "\n#{channel.upcase} CHANNEL:"
strategy.call(budget)
end
end
end
end
# Create different marketing strategies
email_strategy = Proc.new do |budget|
emails_to_send = (budget / 0.05).to_i # $0.05 per email
puts " 📧 Sending #{emails_to_send} personalized emails"
puts " 📊 Expected open rate: 25%"
puts " 📈 Expected conversion rate: 3%"
end
social_media_strategy = Proc.new do |budget|
posts_to_boost = (budget / 25).to_i # $25 per boosted post
puts " 📱 Boosting #{posts_to_boost} social media posts"
puts " 👥 Expected reach: #{posts_to_boost * 5000} people"
puts " 💬 Expected engagement rate: 8%"
end
google_ads_strategy = Proc.new do |budget|
clicks_expected = (budget / 2.50).to_i # $2.50 per click
puts " 🔍 Google Ads campaign"
puts " 👆 Expected clicks: #{clicks_expected}"
puts " 📊 Expected conversion rate: 5%"
end
# Execute a marketing campaign
campaign = MarketingCampaign.new("Spring Product Launch")
campaign.add_strategy(:email, email_strategy)
campaign.add_strategy(:social_media, social_media_strategy)
campaign.add_strategy(:google_ads, google_ads_strategy)
budget_allocation = {
email: 500,
social_media: 750,
google_ads: 1000
}
campaign.execute_campaign(budget_allocation)
# Pattern 2: Observer Pattern - Business event notifications
class BusinessEventSystem
def initialize
@observers = Hash.new { |h, k| h[k] = [] }
end
def subscribe(event_type, &observer_block)
@observers[event_type] << observer_block
puts "👂 Subscribed to #{event_type} events"
end
def notify(event_type, event_data)
puts "\n📡 Broadcasting #{event_type} event:"
@observers[event_type].each do |observer|
observer.call(event_data)
end
end
end
# Set up business event system
events = BusinessEventSystem.new
# Subscribe different departments to relevant events
events.subscribe(:new_customer) do |customer_data|
puts " 🎯 Marketing: Adding #{customer_data[:name]} to email list"
puts " 🎯 Marketing: Assigning to nurture sequence"
end
events.subscribe(:new_customer) do |customer_data|
puts " 🤝 Sales: Creating lead record for #{customer_data[:name]}"
puts " 🤝 Sales: Scheduling follow-up call"
end
events.subscribe(:large_order) do |order_data|
puts " 🏆 Management: Large order alert! $#{order_data[:amount]} from #{order_data[:customer]}"
puts " 🏆 Management: Flagging for personal follow-up"
end
events.subscribe(:large_order) do |order_data|
puts " 📦 Fulfillment: Priority processing for order ##{order_data[:id]}"
puts " 📦 Fulfillment: Ensuring next-day shipping"
end
# Trigger some business events
events.notify(:new_customer, { name: "Acme Corp", email: "[email protected]", industry: "Manufacturing" })
events.notify(:large_order, { id: "ORD-5678", customer: "BigClient Inc", amount: 50000 })
# ==========================================
# 7. PERFORMANCE AND MEMORY CONSIDERATIONS
# ==========================================
puts "\n\n7. PERFORMANCE AND MEMORY CONSIDERATIONS"
puts "-" * 50
puts "\n💡 BUSINESS PERFORMANCE TIPS:"
puts "\n🚀 Speed Considerations:"
puts " • Blocks: Fastest (no object creation)"
puts " • Procs: Moderate (object creation overhead)"
puts " • Lambdas: Moderate (object creation + argument checking)"
puts "\n💾 Memory Considerations:"
puts " • Blocks: Least memory (temporary)"
puts " • Procs: More memory (stored as objects)"
puts " • Lambdas: Similar to Procs"
puts "\n🎯 Best Practices for Business Applications:"
puts " • Use blocks for one-time operations (like processing reports)"
puts " • Use Procs for reusable business logic (like tax calculations)"
puts " • Use lambdas for critical operations (like financial calculations)"
puts " • Cache expensive Procs/lambdas instead of recreating them"
# Example: Caching expensive business calculations
class BusinessCalculator
def initialize
@calculation_cache = {}
end
def get_calculator(calculation_type)
# Cache the Proc so we don't create it every time
@calculation_cache[calculation_type] ||= case calculation_type
when :roi
lambda { |profit, investment| ((profit - investment) / investment.to_f * 100).round(2) }
when :break_even
lambda { |fixed_costs, price_per_unit, variable_cost_per_unit|
(fixed_costs / (price_per_unit - variable_cost_per_unit)).ceil
}
when :markup
lambda { |cost, markup_percentage| cost * (1 + markup_percentage / 100.0) }
end
end
end
calculator = BusinessCalculator.new
# These will reuse cached lambdas
roi_calc = calculator.get_calculator(:roi)
break_even_calc = calculator.get_calculator(:break_even)
puts "\nCached calculation examples:"
puts "ROI: #{roi_calc.call(15000, 10000)}%"
puts "Break-even point: #{break_even_calc.call(50000, 25, 10)} units"
puts "\n" + "=" * 60
puts "KEY CONCEPTS SUMMARY"
puts "=" * 60
puts "\n🧱 BLOCKS are like verbal instructions:"
puts " • Given on the spot for immediate use"
puts " • Can't be saved for later"
puts " • Perfect for 'do this with each item' scenarios"
puts "\n📋 PROCS are like written procedures:"
puts " • Can be saved and reused multiple times"
puts " • Flexible with arguments (forgiving)"
puts " • Great for configurable business logic"
puts "\n📄 LAMBDAS are like formal contracts:"
puts " • Strict about requirements (argument count)"
puts " • Professional and reliable"
puts " • Best for critical business calculations"
puts "\n🎯 BUSINESS TAKEAWAY:"
puts " These tools let you package business logic into reusable pieces"
puts " Choose based on formality: Blocks (casual) → Procs (flexible) → Lambdas (strict)"
puts " This makes your code more organized and business logic more maintainable"
# Ruby Variable Scoping for Business People
# Think of variable scope like information access levels in your company
puts "=" * 60
puts "RUBY VARIABLE SCOPING - COMPANY INFORMATION ACCESS"
puts "=" * 60
# ==========================================
# 1. LOCAL VARIABLES - Department-Level Information
# ==========================================
puts "\n1. LOCAL VARIABLES - Department-Level Information"
puts "-" * 50
# Local variables are like information that exists only within a specific department
# They start with lowercase letters or underscores
# They can't be accessed from outside their "department" (scope)
def sales_department_meeting
# These variables only exist inside this meeting (method)
monthly_target = 100000 # Local variable - only sales team knows this
current_sales = 85000 # Local variable - department-specific data
team_size = 5 # Local variable - internal info
puts "🏢 SALES DEPARTMENT MEETING:"
puts " Monthly target: $#{monthly_target}"
puts " Current sales: $#{current_sales}"
puts " Team size: #{team_size} people"
# Calculate department-specific metrics
if current_sales >= monthly_target
performance_status = "exceeding target"
else
performance_status = "below target"
end
puts " Status: #{performance_status}"
# Local variables die when the method ends (meeting is over)
return "Sales meeting completed"
end
def marketing_department_meeting
# These are completely separate local variables
# Even though they have the same names, they're different "conversations"
monthly_target = 50000 # Different target than sales
current_performance = 42000 # Different metric
team_size = 3 # Different team size
puts "\n🎯 MARKETING DEPARTMENT MEETING:"
puts " Monthly budget: $#{monthly_target}"
puts " Current spend: $#{current_performance}"
puts " Team size: #{team_size} people"
return "Marketing meeting completed"
end
# Run the department meetings
sales_result = sales_department_meeting
marketing_result = marketing_department_meeting
puts "\nMeeting results:"
puts " #{sales_result}"
puts " #{marketing_result}"
# Try to access local variables from outside their scope (this would cause an error)
puts "\nTrying to access department-internal information from outside:"
begin
puts "Sales target: #{monthly_target}" # This will fail - variable doesn't exist here
rescue NameError => e
puts "❌ Error: #{e.message}"
puts " (You can't access department-internal info from outside the department)"
end
# Example: Local variables in different scopes
def project_alpha
project_name = "Alpha"
budget = 250000
puts "\n📊 PROJECT ALPHA SCOPE:"
puts " Project: #{project_name}"
puts " Budget: $#{budget}"
# Creating a sub-scope (like a sub-committee)
3.times do |week|
weekly_progress = (week + 1) * 25 # This only exists in this loop
puts " Week #{week + 1}: #{weekly_progress}% complete"
end
# weekly_progress doesn't exist here - it was only in the loop scope
puts " Project summary complete"
end
project_alpha
# ==========================================
# 2. INSTANCE VARIABLES - Employee Personal Information
# ==========================================
puts "\n\n2. INSTANCE VARIABLES - Employee Personal Information"
puts "-" * 50
# Instance variables are like personal information that belongs to a specific employee
# They start with @ and are accessible throughout that employee's (object's) methods
# Each employee (object) has their own copy of these variables
class Employee
# When an employee is hired (object is created)
def initialize(name, department, salary)
@name = name # @ means "this belongs to THIS specific employee"
@department = department
@salary = salary
@performance_score = 0
@projects_completed = 0
puts "🆕 New employee hired: #{@name} in #{@department}"
end
# Employee methods can access their own information anywhere
def introduce
puts "👋 Hi, I'm #{@name} from #{@department}. I earn $#{@salary}."
end
def complete_project(project_name)
@projects_completed += 1 # Employee updates their own record
@performance_score += 10
puts "✅ #{@name} completed #{project_name}"
puts " Projects completed: #{@projects_completed}"
puts " Performance score: #{@performance_score}"
end
def get_promotion(new_salary, new_department = nil)
old_salary = @salary
@salary = new_salary
@department = new_department if new_department
puts "🎉 #{@name} got promoted!"
puts " Salary: $#{old_salary} → $#{@salary}"
puts " Department: #{@department}" if new_department
end
def annual_review
puts "\n📋 ANNUAL REVIEW for #{@name}:"
puts " Department: #{@department}"
puts " Current salary: $#{@salary}"
puts " Projects completed: #{@projects_completed}"
puts " Performance score: #{@performance_score}"
# Performance-based raise calculation using instance variables
if @performance_score >= 50
bonus = @salary * 0.10
puts " 🏆 Excellent performance! Bonus: $#{bonus}"
elsif @performance_score >= 30
bonus = @salary * 0.05
puts " 👍 Good performance! Bonus: $#{bonus}"
else
puts " 📈 Needs improvement"
end
end
end
# Creating employees (each gets their own instance variables)
puts "\nHiring employees:"
alice = Employee.new("Alice Johnson", "Engineering", 75000)
bob = Employee.new("Bob Smith", "Sales", 65000)
carol = Employee.new("Carol Davis", "Marketing", 60000)
# Each employee has their own separate instance variables
puts "\nEmployee introductions:"
alice.introduce
bob.introduce
carol.introduce
# Employees working independently (each updates their own variables)
puts "\nWork activities:"
alice.complete_project("Website Redesign")
alice.complete_project("Database Optimization")
bob.complete_project("Q1 Sales Campaign")
bob.complete_project("Client Onboarding System")
bob.complete_project("Sales Training Program")
carol.complete_project("Brand Guidelines")
# Promotions (changing instance variables)
puts "\nPromotions:"
alice.get_promotion(85000)
bob.get_promotion(70000, "Sales Management")
# Annual reviews (accessing all instance variables)
alice.annual_review
bob.annual_review
carol.annual_review
# ==========================================
# 3. CLASS VARIABLES - Company-Wide Policies
# ==========================================
puts "\n\n3. CLASS VARIABLES - Company-Wide Policies"
puts "-" * 50
# Class variables are like company-wide policies that apply to ALL employees
# They start with @@ and are shared by all instances of the class
# Think of them as "company handbook" information
class Company
# Class variables - shared by ALL employees in the company
@@company_name = "Tech Innovations Inc"
@@total_employees = 0
@@company_revenue = 0
@@health_insurance_provider = "HealthCorp"
@@vacation_days_per_year = 20
def initialize(employee_name, department, salary)
@employee_name = employee_name # Instance variable - belongs to this employee
@department = department
@salary = salary
# Update company-wide statistics (class variables)
@@total_employees += 1
@@company_revenue += salary # Assume salary contributes to revenue planning
puts "🏢 #{@employee_name} joined #{@@company_name}"
puts " Total employees now: #{@@total_employees}"
end
# Method to access company-wide information
def company_info
puts "\n🏢 COMPANY INFORMATION (same for all employees):"
puts " Company: #{@@company_name}"
puts " Total employees: #{@@total_employees}"
puts " Projected revenue: $#{@@company_revenue}"
puts " Health insurance: #{@@health_insurance_provider}"
puts " Vacation days: #{@@vacation_days_per_year} per year"
end
def personal_info
puts "\n👤 PERSONAL INFORMATION (specific to #{@employee_name}):"
puts " Name: #{@employee_name}"
puts " Department: #{@department}"
puts " Salary: $#{@salary}"
end
# Class method to change company-wide policies
def self.update_company_policy(policy, new_value)
case policy
when :vacation_days
@@vacation_days_per_year = new_value
puts "📋 Company policy updated: Vacation days changed to #{new_value}"
when :health_insurance
@@health_insurance_provider = new_value
puts "📋 Company policy updated: Health insurance changed to #{new_value}"
when :company_name
@@company_name = new_value
puts "📋 Company rebranded to: #{new_value}"
end
end
# Class method to get company statistics
def self.company_statistics
puts "\n📊 COMPANY STATISTICS:"
puts " Company: #{@@company_name}"
puts " Total employees: #{@@total_employees}"
puts " Total salary budget: $#{@@company_revenue}"
puts " Average salary: $#{@@company_revenue / @@total_employees}" if @@total_employees > 0
end
end
# Hiring employees (each one updates the class variables)
puts "\nBuilding our company:"
emp1 = Company.new("David Wilson", "Engineering", 80000)
emp2 = Company.new("Emma Brown", "Sales", 70000)
emp3 = Company.new("Frank Miller", "Marketing", 65000)
# All employees see the same company information (class variables)
puts "\nCompany information as seen by different employees:"
emp1.company_info # Same information for everyone
emp2.company_info # Same information for everyone
# But personal information is different (instance variables)
puts "\nPersonal information varies by employee:"
emp1.personal_info # Different for each employee
emp2.personal_info # Different for each employee
emp3.personal_info # Different for each employee
# Changing company-wide policies affects everyone
puts "\nUpdating company policies:"
Company.update_company_policy(:vacation_days, 25)
Company.update_company_policy(:health_insurance, "BetterHealth Inc")
# All employees now see the updated policies
puts "\nUpdated company info (same for all employees):"
emp1.company_info
# Company-wide statistics
Company.company_statistics
# ==========================================
# 4. GLOBAL VARIABLES - Industry Standards
# ==========================================
puts "\n\n4. GLOBAL VARIABLES - Industry-Wide Standards"
puts "-" * 50
# Global variables are like industry-wide standards that everyone follows
# They start with $ and can be accessed from anywhere in the program
# Think of them as "universal business standards"
# Define global variables (industry standards)
$minimum_wage = 15.00 # Industry minimum wage
$standard_work_week = 40 # Standard work week hours
$overtime_multiplier = 1.5 # Overtime pay multiplier
$industry_tax_rate = 0.15 # Standard industry tax rate
puts "💼 INDUSTRY STANDARDS (Global Variables):"
puts " Minimum wage: $#{$minimum_wage}/hour"
puts " Standard work week: #{$standard_work_week} hours"
puts " Overtime multiplier: #{$overtime_multiplier}x"
puts " Industry tax rate: #{($industry_tax_rate * 100).to_i}%"
class PayrollSystem
def initialize(company_name)
@company_name = company_name # Instance variable
puts "\n💰 Payroll system initialized for #{@company_name}"
end
def calculate_weekly_pay(employee_name, hourly_rate, hours_worked)
puts "\n📊 Calculating pay for #{employee_name}:"
puts " Hourly rate: $#{hourly_rate}"
puts " Hours worked: #{hours_worked}"
# Use global variables for industry standards
if hourly_rate < $minimum_wage
puts " ⚠️ Adjusting to minimum wage: $#{$minimum_wage}"
hourly_rate = $minimum_wage
end
# Calculate regular and overtime pay using global standards
if hours_worked <= $standard_work_week
regular_pay = hours_worked * hourly_rate
overtime_pay = 0
total_hours_overtime = 0
else
regular_pay = $standard_work_week * hourly_rate
overtime_hours = hours_worked - $standard_work_week
overtime_pay = overtime_hours * hourly_rate * $overtime_multiplier
total_hours_overtime = overtime_hours
end
gross_pay = regular_pay + overtime_pay
taxes = gross_pay * $industry_tax_rate
net_pay = gross_pay - taxes
puts " Regular pay (#{[$standard_work_week, hours_worked].min} hours): $#{regular_pay.round(2)}"
if total_hours_overtime > 0
puts " Overtime pay (#{total_hours_overtime} hours at #{$overtime_multiplier}x): $#{overtime_pay.round(2)}"
end
puts " Gross pay: $#{gross_pay.round(2)}"
puts " Taxes (#{($industry_tax_rate * 100).to_i}%): $#{taxes.round(2)}"
puts " Net pay: $#{net_pay.round(2)}"
net_pay.round(2)
end
end
# Different companies using the same global standards
tech_payroll = PayrollSystem.new("Tech Innovations")
retail_payroll = PayrollSystem.new("Retail Solutions")
# Calculate pay using global industry standards
tech_payroll.calculate_weekly_pay("Alice", 25.00, 42) # 2 hours overtime
retail_payroll.calculate_weekly_pay("Bob", 12.00, 35) # Below minimum wage, under 40 hours
tech_payroll.calculate_weekly_pay("Charlie", 30.00, 50) # 10 hours overtime
# Industry standards change (affecting everyone globally)
puts "\n📢 INDUSTRY UPDATE: New standards announced!"
$minimum_wage = 16.50
$overtime_multiplier = 1.75
puts " New minimum wage: $#{$minimum_wage}/hour"
puts " New overtime multiplier: #{$overtime_multiplier}x"
# Recalculate with new global standards
puts "\nRecalculating with new industry standards:"
retail_payroll.calculate_weekly_pay("Bob", 12.00, 35) # Now gets higher minimum wage
# ==========================================
# 5. SCOPE HIERARCHY AND VARIABLE LOOKUP
# ==========================================
puts "\n\n5. SCOPE HIERARCHY - How Ruby Finds Variables"
puts "-" * 50
# Ruby looks for variables in a specific order (like a company hierarchy)
# This is called the "scope chain" or "variable lookup"
$company_motto = "Innovation Through Excellence" # Global variable
class Department
@@department_budget = 500000 # Class variable (shared by all departments)
def initialize(dept_name, manager_name)
@dept_name = dept_name # Instance variable (specific to this department)
@manager = manager_name
end
def demonstrate_variable_lookup
local_meeting_agenda = "Q3 Planning" # Local variable (only in this method)
puts "\n🔍 VARIABLE LOOKUP DEMONSTRATION:"
puts " Method: demonstrate_variable_lookup"
puts " Department: #{@dept_name} (instance variable)"
puts " Manager: #{@manager} (instance variable)"
puts "\n📊 Ruby's Variable Search Order:"
puts " 1. Local variables first: #{local_meeting_agenda}"
puts " 2. Instance variables (@): Department #{@dept_name}, Manager #{@manager}"
puts " 3. Class variables (@@): Budget $#{@@department_budget}"
puts " 4. Global variables ($): #{$company_motto}"
# Demonstrate variable shadowing (when names conflict)
demonstrate_shadowing
end
def demonstrate_shadowing
# Local variable with same name as global variable
company_motto = "Local meeting motto: Focus and Execute" # Shadows the global $company_motto
puts "\n👥 VARIABLE SHADOWING EXAMPLE:"
puts " Local variable 'company_motto': #{company_motto}"
puts " Global variable '$company_motto': #{$company_motto}"
puts " (Local variable 'shadows' or hides the global one)"
end
def access_different_scopes
puts "\n🎯 ACCESSING DIFFERENT VARIABLE SCOPES:"
# Local variable
current_project = "Website Redesign"
puts " Local variable: #{current_project}"
# Instance variable (department-specific)
puts " Instance variable: #{@dept_name} department"
# Class variable (company-wide department info)
puts " Class variable: $#{@@department_budget} total budget"
# Global variable (universal)
puts " Global variable: #{$company_motto}"
# What happens when we try to access a variable that doesn't exist?
begin
puts " Trying to access non-existent variable: #{non_existent_var}"
rescue NameError => e
puts " ❌ Error: #{e.message}"
puts " (Ruby searched all scopes but couldn't find this variable)"
end
end
end
# Create departments and demonstrate variable lookup
engineering = Department.new("Engineering", "Sarah Chen")
marketing = Department.new("Marketing", "Mike Johnson")
engineering.demonstrate_variable_lookup
marketing.access_different_scopes
# ==========================================
# 6. PRACTICAL BUSINESS SCENARIOS
# ==========================================
puts "\n\n6. PRACTICAL BUSINESS SCENARIOS"
puts "-" * 50
# Scenario 1: Multi-level business hierarchy with proper variable scoping
class Corporation
@@total_revenue = 0 # Class variable - company-wide revenue
@@employee_count = 0 # Class variable - total employees
def self.add_revenue(amount)
@@total_revenue += amount
end
def self.hire_employee
@@employee_count += 1
end
def self.corporate_report
puts "\n🏢 CORPORATE REPORT:"
puts " Total Revenue: $#{@@total_revenue}"
puts " Total Employees: #{@@employee_count}"
puts " Revenue per Employee: $#{(@@total_revenue / @@employee_count.to_f).round(2)}"
end
end
class BusinessUnit < Corporation
def initialize(unit_name, initial_budget)
@unit_name = unit_name # Instance variable - this unit's name
@budget = initial_budget # Instance variable - this unit's budget
@quarterly_sales = [] # Instance variable - this unit's sales history
self.class.hire_employee # Update corporate employee count
puts "🏭 Created business unit: #{@unit_name} with budget $#{@budget}"
end
def record_quarterly_sales(q1, q2, q3, q4)
@quarterly_sales = [q1, q2, q3, q4] # Instance variable updated
total_sales = @quarterly_sales.sum
# Update corporate revenue (class variable)
Corporation.add_revenue(total_sales)
puts "\n📈 #{@unit_name} Annual Sales:"
@quarterly_sales.each_with_index do |sales, index|
puts " Q#{index + 1}: $#{sales}"
end
puts " Total: $#{total_sales}"
# Local variable for performance calculation
performance_rating = if total_sales > @budget * 1.2
"Excellent"
elsif total_sales > @budget
"Good"
else
"Needs Improvement"
end
puts " Performance: #{performance_rating} (Budget: $#{@budget})"
end
def unit_summary
puts "\n📊 UNIT SUMMARY for #{@unit_name}:"
puts " Budget: $#{@budget} (instance variable)"
puts " Quarterly Sales: #{@quarterly_sales} (instance variable)"
if @quarterly_sales.any?
puts " Best Quarter: Q#{@quarterly_sales.index(@quarterly_sales.max) + 1} ($#{@quarterly_sales.max})"
end
end
end
# Create business units (each with their own instance variables)
puts "\nCreating business units:"
tech_division = BusinessUnit.new("Technology Division", 2000000)
sales_division = BusinessUnit.new("Sales Division", 1500000)
marketing_division = BusinessUnit.new("Marketing Division", 800000)
# Record sales (updating instance and class variables)
tech_division.record_quarterly_sales(450000, 520000, 480000, 610000)
sales_division.record_quarterly_sales(380000, 420000, 390000, 450000)
marketing_division.record_quarterly_sales(180000, 220000, 210000, 240000)
# Show individual unit summaries (instance variables)
tech_division.unit_summary
sales_division.unit_summary
# Show corporate overview (class variables)
Corporation.corporate_report
# ==========================================
# 7. VARIABLE SCOPE BEST PRACTICES
# ==========================================
puts "\n\n7. VARIABLE SCOPE BEST PRACTICES"
puts "-" * 50
class BestPracticesExample
# Class variables for company-wide settings
@@company_name = "Best Practices Corp"
@@default_benefits_package = "Standard"
def initialize(employee_name)
@employee_name = employee_name # Instance variable for employee-specific data
@hire_date = Time.now.strftime("%Y-%m-%d")
@projects = []
puts "✅ #{@employee_name} hired on #{@hire_date}"
end
def start_project(project_name, budget)
# Local variables for method-specific calculations
project_start_date = Time.now.strftime("%Y-%m-%d")
estimated_duration = calculate_duration(budget) # Local variable from method call
# Update instance variable (employee's project list)
@projects << {
name: project_name,
budget: budget,
start_date: project_start_date,
duration: estimated_duration
}
puts "🚀 #{@employee_name} started project: #{project_name}"
puts " Budget: $#{budget}"
puts " Estimated duration: #{estimated_duration} weeks"
puts " Start date: #{project_start_date}"
end
private
def calculate_duration(budget)
# Local variable calculation - only exists in this method
base_weeks = 4
complexity_factor = budget / 10000.0
duration = (base_weeks + complexity_factor).round
[duration, 2].max # Minimum 2 weeks
end
public
def employee_report
puts "\n👤 EMPLOYEE REPORT: #{@employee_name}"
puts " Company: #{@@company_name} (class variable)"
puts " Hire Date: #{@hire_date} (instance variable)"
puts " Benefits: #{@@default_benefits_package} (class variable)"
puts " Active Projects: #{@projects.length} (instance variable)"
@projects.each do |project|
puts " • #{project[:name]} ($#{project[:budget]})"
end
end
end
puts "\n🎯 DEMONSTRATING BEST PRACTICES:"
# Create employees with proper variable usage
john = BestPracticesExample.new("John Smith")
jane = BestPracticesExample.new("Jane Doe")
# Each employee manages their own projects (instance variables)
john.start_project("E-commerce Platform", 150000)
john.start_project("Mobile App", 80000)
jane.start_project("Data Analytics", 120000)
jane.start_project("Security Audit", 60000)
# Generate reports showing proper variable scoping
john.employee_report
jane.employee_report
# ==========================================
# 8. COMMON SCOPING MISTAKES AND SOLUTIONS
# ==========================================
puts "\n\n8. COMMON SCOPING MISTAKES AND SOLUTIONS"
puts "-" * 50
puts "\n❌ COMMON MISTAKE #1: Confusing local and instance variables"
class WrongWay
def initialize(name)
name = name # Wrong! This creates a local variable, not an instance variable
end
def get_name
name # This will fail - local variable doesn't exist here
rescue NameError
"Name not found - local variable doesn't persist between methods"
end
end
class RightWay
def initialize(name)
@name = name # Right! This creates an instance variable
end
def get_name
@name # This works - instance variable persists across methods
end
end
wrong_employee = WrongWay.new("Alice")
right_employee = RightWay.new("Bob")
puts "Wrong way result: #{wrong_employee.get_name}"
puts "Right way result: #{right_employee.get_name}"
puts "\n❌ COMMON MISTAKE #2: Overusing global variables"
# Wrong approach - everything global
$user_name = "Alice"
$user_salary = 75000
$user_department = "Engineering"
def wrong_employee_info
puts "❌ Bad practice: #{$user_name} earns $#{$user_salary} in #{$user_department}"
end
# Right approach - proper encapsulation
class ProperEmployee
def initialize(name, salary, department)
@name = name # Instance variable - belongs to this employee
@salary = salary
@department = department
end
def employee_info
puts "✅ Good practice: #{@name} earns $#{@salary} in #{@department}"
end
end
puts "\nDemonstrating global variable problems:"
wrong_employee_info # Uses global variables
# What happens when we need multiple employees?
$user_name = "Bob" # Oops! This overwrites Alice's data
$user_salary = 80000
$user_department = "Sales"
wrong_employee_info # Now Alice's data is lost!
puts "\nProper approach with instance variables:"
alice_proper = ProperEmployee.new("Alice", 75000, "Engineering")
bob_proper = ProperEmployee.new("Bob", 80000, "Sales")
alice_proper.employee_info # Alice's data is safe
bob_proper.employee_info # Bob's data is separate
puts "\n❌ COMMON MISTAKE #3: Variable name conflicts"
class VariableConflicts
@@company_bonus = 5000 # Class variable
def initialize(name)
@name = name
@company_bonus = 3000 # Instance variable with same name - confusing!
end
def show_bonus_confusion
company_bonus = 1000 # Local variable with same name - very confusing!
puts "🤔 CONFUSING VARIABLE NAMES:"
puts " Local variable 'company_bonus': $#{company_bonus}"
puts " Instance variable '@company_bonus': $#{@company_bonus}"
puts " Class variable '@@company_bonus': $#{@@company_bonus}"
puts " This is confusing and error-prone!"
end
def clear_naming_example
monthly_individual_bonus = 1000 # Clear local variable name
puts "\n✅ CLEAR VARIABLE NAMES:"
puts " Local: monthly_individual_bonus = $#{monthly_individual_bonus}"
puts " Instance: @company_bonus = $#{@company_bonus}"
puts " Class: @@company_bonus = $#{@@company_bonus}"
puts " Much clearer what each variable represents!"
end
end
confused_employee = VariableConflicts.new("Charlie")
confused_employee.show_bonus_confusion
confused_employee.clear_naming_example
# ==========================================
# 9. SCOPE AND MEMORY MANAGEMENT
# ==========================================
puts "\n\n9. SCOPE AND MEMORY MANAGEMENT"
puts "-" * 50
puts "\n💾 MEMORY IMPLICATIONS OF VARIABLE SCOPES:"
def demonstrate_memory_usage
puts "\n🔍 Memory and Scope Relationship:"
# Local variables - cleaned up when method ends
large_local_data = Array.new(1000) { rand(1000) }
puts " ✅ Local variables: Automatically cleaned up when method ends"
puts " Created array with #{large_local_data.length} elements"
# The large_local_data will be garbage collected when this method ends
return "Local variables cleaned up automatically"
end
class MemoryExample
def initialize
# Instance variables - live as long as the object exists
@persistent_data = Array.new(500) { rand(1000) }
@@class_shared_data ||= Array.new(100) { rand(1000) } # Class variable
puts " ⚠️ Instance variables: Live as long as the object exists"
puts " ⚠️ Class variables: Live for entire program duration"
end
def add_more_data
# This adds to the instance variable - increases memory usage
@persistent_data += Array.new(100) { rand(1000) }
puts " 📈 Instance variable grew to #{@persistent_data.length} elements"
end
def create_temporary_calculation
# Local variables for calculations
temp_results = @persistent_data.map { |x| x * 2 }
final_result = temp_results.sum
# temp_results will be cleaned up when method ends
puts " 🧮 Temporary calculation completed: #{final_result}"
puts " Temporary array will be garbage collected"
final_result
end
end
# Demonstrate memory management
result = demonstrate_memory_usage
puts "Result: #{result}"
memory_example = MemoryExample.new
memory_example.add_more_data
memory_example.create_temporary_calculation
puts "\n💡 MEMORY BEST PRACTICES:"
puts " • Use local variables for temporary calculations"
puts " • Use instance variables for object-specific data"
puts " • Use class variables sparingly (they never get cleaned up)"
puts " • Avoid global variables (they live forever and pollute global namespace)"
# ==========================================
# 10. REAL-WORLD BUSINESS APPLICATION
# ==========================================
puts "\n\n10. REAL-WORLD BUSINESS APPLICATION"
puts "-" * 50
# Complete business system demonstrating proper variable scoping
$tax_rate = 0.08 # Global - universal tax rate
$currency = "USD" # Global - universal currency
class InvoiceSystem
@@next_invoice_number = 1000 # Class variable - shared invoice numbering
@@total_invoices_generated = 0 # Class variable - company statistics
def initialize(company_name, address)
@company_name = company_name # Instance variable - this company's info
@company_address = address
@invoices = [] # Instance variable - this company's invoices
puts "🏢 Invoice system initialized for #{@company_name}"
end
def create_invoice(client_name, items)
# Local variables for this specific invoice
invoice_number = @@next_invoice_number
invoice_date = Time.now.strftime("%Y-%m-%d")
# Calculate totals using local variables
subtotal = items.sum { |item| item[:quantity] * item[:price] }
tax_amount = subtotal * $tax_rate
total_amount = subtotal + tax_amount
# Create invoice hash (local variable)
invoice = {
number: invoice_number,
date: invoice_date,
client: client_name,
items: items,
subtotal: subtotal,
tax: tax_amount,
total: total_amount
}
# Update instance and class variables
@invoices << invoice
@@next_invoice_number += 1
@@total_invoices_generated += 1
puts "\n📄 INVOICE ##{invoice_number} CREATED"
puts " Company: #{@company_name}"
puts " Client: #{client_name}"
puts " Date: #{invoice_date}"
puts " Items: #{items.length}"
puts " Subtotal: #{format_currency(subtotal)}"
puts " Tax (#{($tax_rate * 100).to_i}%): #{format_currency(tax_amount)}"
puts " Total: #{format_currency(total_amount)}"
invoice_number
end
def company_report
# Access instance variables for company-specific data
total_revenue = @invoices.sum { |inv| inv[:total] }
average_invoice = @invoices.length > 0 ? total_revenue / @invoices.length : 0
puts "\n📊 COMPANY REPORT: #{@company_name}"
puts " Address: #{@company_address}"
puts " Invoices Generated: #{@invoices.length}"
puts " Total Revenue: #{format_currency(total_revenue)}"
puts " Average Invoice: #{format_currency(average_invoice)}"
end
def self.system_statistics
# Access class variables for system-wide statistics
puts "\n📈 SYSTEM STATISTICS:"
puts " Total Invoices Generated: #{@@total_invoices_generated}"
puts " Next Invoice Number: #{@@next_invoice_number}"
puts " Global Tax Rate: #{($tax_rate * 100).to_i}%"
puts " Currency: #{$currency}"
end
private
def format_currency(amount)
# Local variable for formatting
formatted = "%.2f" % amount
"$#{formatted} #{$currency}"
end
end
# Create multiple companies (each with their own instance variables)
puts "\nSetting up invoice systems:"
tech_company = InvoiceSystem.new("Tech Solutions Inc", "123 Innovation Drive")
consulting_firm = InvoiceSystem.new("Business Consultants LLC", "456 Strategy Street")
# Generate invoices (local variables in each method call)
puts "\nGenerating invoices:"
tech_items = [
{ description: "Web Development", quantity: 1, price: 5000 },
{ description: "Database Setup", quantity: 1, price: 2000 },
{ description: "Testing", quantity: 20, price: 100 }
]
consulting_items = [
{ description: "Strategy Consultation", quantity: 40, price: 150 },
{ description: "Market Analysis", quantity: 1, price: 3000 }
]
tech_company.create_invoice("Acme Corp", tech_items)
consulting_firm.create_invoice("Global Industries", consulting_items)
tech_company.create_invoice("StartupXYZ", [
{ description: "MVP Development", quantity: 1, price: 8000 }
])
# Generate reports (showing different variable scopes)
tech_company.company_report # Uses instance variables
consulting_firm.company_report # Uses different instance variables
InvoiceSystem.system_statistics # Uses class variables and globals
puts "\n" + "=" * 60
puts "KEY CONCEPTS SUMMARY"
puts "=" * 60
puts "\n🏢 LOCAL VARIABLES (lowercase_name):"
puts " • Like department-level information"
puts " • Only exist within their method/block"
puts " • Automatically cleaned up when scope ends"
puts " • Use for: temporary calculations, method parameters"
puts "\n👤 INSTANCE VARIABLES (@name):"
puts " • Like employee personal information"
puts " • Belong to specific object instances"
puts " • Live as long as the object exists"
puts " • Use for: object-specific data, state that persists"
puts "\n🏢 CLASS VARIABLES (@@name):"
puts " • Like company-wide policies"
puts " • Shared by all instances of a class"
puts " • Live for entire program duration"
puts " • Use for: shared counters, company-wide settings"
puts "\n🌍 GLOBAL VARIABLES ($name):"
puts " • Like industry-wide standards"
puts " • Accessible from anywhere in the program"
puts " • Live for entire program duration"
puts " • Use sparingly for: universal constants, system-wide settings"
puts "\n🎯 BUSINESS TAKEAWAYS:"
puts " • Choose scope based on who needs access to the information"
puts " • Local = temporary work, Instance = personal data"
puts " • Class = company policies, Global = industry standards"
puts " • Proper scoping makes code organized, secure, and maintainable"
puts " • When in doubt, use the most restrictive scope that works"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment