Ruby Classes
Ruby Classes and Objects: The Blueprint of OOP
Section titled “Ruby Classes and Objects: The Blueprint of OOP”Ruby is a pure Object-Oriented Programming (OOP) language. Key OOP principles include:
- Data Encapsulation: Bundling data (attributes) and methods that operate on the data within a single unit (an object). Access to the internal state is controlled.
- Data Abstraction: Hiding complex implementation details and exposing only essential features of an object.
- Polymorphism: The ability of objects of different classes to respond to the same message (method call) in different, class-specific ways.
- Inheritance: Allowing a new class (subclass) to inherit properties and methods from an existing class (superclass), promoting code reuse and establishing relationships.
In Ruby, everything is an object. A class is a blueprint for creating objects. An object is an instance of a class. For example, if String is a class, then "hello" is an object (an instance of String).
Defining a Class in Ruby:
Section titled “Defining a Class in Ruby:”A class definition starts with the class keyword, followed by the class name (which must begin with a capital letter by convention, e.g., CamelCase), and ends with the end keyword.
class Vehicle # Class content (attributes and methods) goes hereendVariables in a Ruby Class:
Section titled “Variables in a Ruby Class:”Ruby supports several types of variables within the context of classes:
- Local Variables: Defined within a method. Their scope is limited to that method. They begin with a lowercase letter or
_(e.g.,my_var). - Instance Variables: Belong to a specific instance (object) of a class. They hold the state of an object. Their names start with an
@symbol (e.g.,@color). Each object can have different values for its instance variables. - Class Variables: Shared among all instances of a class, and also accessible by the class itself. Their names start with
@@(e.g.,@@count). Changes to a class variable are visible to all instances. Use with caution, especially with inheritance, as their behavior can sometimes be surprising. - Global Variables: Accessible from anywhere in the program. Their names start with a
$symbol (e.g.,$debug_mode). Global variables should be used sparingly as they can make code harder to maintain and debug.
Example: A Simple Car Class
Section titled “Example: A Simple Car Class”#!/usr/bin/ruby
class Car # Class variable to keep track of the number of cars created @@number_of_cars = 0
# Shortcut for creating getter and setter methods for @color and @make # attr_reader :color # Only getter # attr_writer :color # Only setter attr_accessor :color, :make # Both getter and setter
# The initialize method is a special constructor called when Car.new is invoked def initialize(make, color) @make = make # Instance variable @color = color # Instance variable @@number_of_cars += 1 puts "Initialized a #{@color} #{@make}." end
# Instance method def start_engine puts "The #{@make}'s engine roars to life!" end
# Class method (note the 'self.') def self.total_cars_created "Total cars created: #{@@number_of_cars}" endend
# Creating Objects (Instances of the Car class)my_car = Car.new("Toyota", "Red")her_car = Car.new("Honda", "Blue")
# Accessing instance variables (via attr_accessor)puts "My car is a #{my_car.color} #{my_car.make}."my_car.color = "Silver" # Using the setterputs "My car is now #{my_car.color}."
# Calling instance methodsmy_car.start_engineher_car.start_engine
# Calling a class methodputs Car.total_cars_createdThis will produce output similar to:
Initialized a Red Toyota.Initialized a Blue Honda.My car is a Red Toyota.My car is now Silver.The Toyota's engine roars to life!The Honda's engine roars to life!Total cars created: 2The initialize Method (Constructor):
Section titled “The initialize Method (Constructor):”The initialize method is a special private method in Ruby classes. It’s automatically called when you create a new object using ClassName.new. It’s primarily used to set the initial state of an object by assigning values to its instance variables.
Instance Methods and Class Methods:
Section titled “Instance Methods and Class Methods:”Instance methods operate on an instance of the class (an object). They have access to the object’s instance variables (e.g., start_engine in the Car example).
Class methods are called on the class itself, not on an instance. They are defined by prefixing the method name with self. (e.g., self.total_cars_created). They do not have access to an instance’s variables but can access class variables.
Attribute Accessors (attr_reader, attr_writer, attr_accessor):
Section titled “Attribute Accessors (attr_reader, attr_writer, attr_accessor):”Ruby provides convenient shortcuts for creating common getter and setter methods for instance variables:
attr_reader :variable_namecreates a getter method (e.g.,def variable_name; @variable_name; end).attr_writer :variable_namecreates a setter method (e.g.,def variable_name=(value); @variable_name = value; end).attr_accessor :variable_namecreates both a getter and a setter method.
Using these accessors makes code more concise and idiomatic.
Method Visibility: public, private, protected
Section titled “Method Visibility: public, private, protected”Ruby controls access to methods using visibility keywords:
public: Methods are accessible from anywhere. This is the default visibility.private: Methods can only be called by other methods within the same class instance (implicitly, withoutself.as a receiver, except for setter methodsself.foo =). They are not accessible by subclasses or directly on an object.protected: Methods can be called by instances of the defining class and its subclasses. They can be called with an explicit receiver (e.g.,other_object.protected_method) as long asother_objectis an instance of the same class or a subclass of the caller’s class.
class BankAccount attr_reader :balance
def initialize(initial_deposit) @balance = initial_deposit end
def deposit(amount) @balance += amount log_transaction("Deposit: #{amount}") end
def withdraw(amount) if can_withdraw?(amount) @balance -= amount log_transaction("Withdrawal: #{amount}") else puts "Insufficient funds!" end end
# Protected: Accessible by BankAccount and its subclasses protected def can_withdraw?(amount) @balance >= amount end
# Private: Only accessible within this BankAccount instance private def log_transaction(message) puts "[LOG] #{Time.now}: #{message}, New Balance: #{@balance}" endend
account = BankAccount.new(100)account.deposit(50)account.withdraw(30)# account.log_transaction("test") # This would raise NoMethodError (private)# account.can_withdraw?(10) # This would raise NoMethodError (protected, if called from outside directly)Practical Applications:
Classes and objects are the cornerstone of most Ruby applications. They are used to model real-world entities (like users, products, orders), abstract concepts (like a database connection or a file parser), and to organize code into reusable and maintainable components. Frameworks like Ruby on Rails heavily rely on class-based structures (Models, Views, Controllers).