This tutorial provides a comprehensive guide to understanding and using access modifiers in Ruby. Learn how to control the visibility of methods and attributes using `public`, `protected`, and `private` keywords. Each step builds on the previous one, with practical examples and engaging practice exercises.
Step 1: Understanding Access Modifiers
Access modifiers in Ruby determine the visibility of methods and attributes within a class. There are three main access levels: public, protected, and private. By default, all methods in Ruby are public unless specified otherwise.
class MyClass
def public_method
puts 'This is a public method'
end
private
def private_method
puts 'This is a private method'
end
endPractice Exercise
Create a class Person with a public method greet that prints 'Hello!' and a private method secret that prints 'This is a secret.' Call both methods from outside the class and observe the behavior.
Show Solution
class Person
def greet
puts 'Hello!'
end
private
def secret
puts 'This is a secret.'
end
end
person = Person.new
person.greet # Output: Hello!
person.secret # Error: private method `secret' calledStep 2: Using the `private` Modifier
The private modifier restricts access to methods within the class itself. Private methods cannot be called from outside the class, but they can be used internally by other methods.
class BankAccount
def initialize(balance)
@balance = balance
end
def show_balance
puts "Your balance is: #{@balance}"
end
private
def log_transaction
puts 'Transaction logged'
end
endPractice Exercise
Create a class Calculator with a public method add that takes two numbers and returns their sum. Add a private method log_operation that prints 'Operation logged' whenever add is called.
Show Solution
class Calculator
def add(a, b)
log_operation
a + b
end
private
def log_operation
puts 'Operation logged'
end
end
calc = Calculator.new
puts calc.add(3, 4) # Output: Operation logged
# 7Step 3: Using the `protected` Modifier
The protected modifier allows methods to be accessed within the class and by instances of the same class or its subclasses. This is useful for methods that need to be shared among related objects.
class Animal
def initialize(name)
@name = name
end
protected
def speak
puts "#{@name} makes a sound"
end
end
class Dog < Animal
def bark
speak
end
endPractice Exercise
Create a class Employee with a protected method calculate_bonus that returns 10% of the salary. Create a subclass Manager that overrides calculate_bonus to return 20% of the salary. Ensure the method is accessible within the class hierarchy.
Show Solution
class Employee
def initialize(salary)
@salary = salary
end
protected
def calculate_bonus
@salary * 0.10
end
end
class Manager < Employee
def calculate_bonus
@salary * 0.20
end
end
manager = Manager.new(50000)
puts manager.calculate_bonus # Output: 10000.0Step 4: Combining Access Modifiers
You can combine access modifiers within a class to create a hierarchy of visibility. For example, you might have public methods for external use, protected methods for internal use, and private methods for implementation details.
class Vehicle
def start_engine
puts 'Engine started'
end
protected
def check_fuel
puts 'Fuel level checked'
end
private
def log_maintenance
puts 'Maintenance logged'
end
endPractice Exercise
Create a class Library with a public method check_out_book, a protected method update_inventory, and a private method log_transaction. Ensure each method is used appropriately within the class.
Show Solution
class Library
def check_out_book(book)
update_inventory(book)
log_transaction(book)
puts "#{book} checked out"
end
protected
def update_inventory(book)
puts "Inventory updated for #{book}"
end
private
def log_transaction(book)
puts "Transaction logged for #{book}"
end
end
library = Library.new
library.check_out_book('1984') # Output: Inventory updated for 1984
# Transaction logged for 1984
# 1984 checked outStep 5: Real-World Application: Building a Secure System
In real-world applications, access modifiers are crucial for building secure and maintainable systems. For example, you might use private methods to handle sensitive data and protected methods to share functionality among related classes.
class User
def initialize(username, password)
@username = username
@password = password
end
def authenticate(input_password)
if input_password == @password
puts 'Authentication successful'
else
puts 'Authentication failed'
end
end
private
def encrypt_password
# Encryption logic here
end
endPractice Exercise
Create a class Bank with a public method transfer_funds that transfers money between accounts. Use a protected method validate_transaction to check if the transaction is valid and a private method log_transaction to record the transaction.
Show Solution
class Bank
def transfer_funds(from_account, to_account, amount)
if validate_transaction(from_account, amount)
from_account.balance -= amount
to_account.balance += amount
log_transaction(from_account, to_account, amount)
puts 'Transfer successful'
else
puts 'Transfer failed'
end
end
protected
def validate_transaction(account, amount)
account.balance >= amount
end
private
def log_transaction(from_account, to_account, amount)
puts "Transaction logged: #{amount} transferred from #{from_account.id} to #{to_account.id}"
end
end
class Account
attr_accessor :balance, :id
def initialize(id, balance)
@id = id
@balance = balance
end
end
account1 = Account.new(1, 1000)
account2 = Account.new(2, 500)
bank = Bank.new
bank.transfer_funds(account1, account2, 200) # Output: Transfer successful
# Transaction logged: 200 transferred from 1 to 2Sign in to take Cornell notes on this lesson — they save automatically and stay with your account.