The Complete Ruby Language Guide
Master Ruby — the elegant, expressive language designed for programmer happiness, powering Ruby on Rails and thousands of web applications.
Why Learn Ruby?
Ruby was created by Yukihiro "Matz" Matsumoto and released in 1995. Matz designed Ruby to make programming fun and to prioritize the developer's experience over machine efficiency. The language follows the principle of least surprise — it behaves the way an experienced programmer would expect.
Ruby gained massive popularity through Ruby on Rails, a web framework that transformed how web applications are built. Rails' "convention over configuration" philosophy enables rapid development, powering GitHub, Shopify, Airbnb, and Basecamp.
Ruby is fully object-oriented — everything is an object, including numbers, strings, and even nil. This consistency makes it remarkably readable and expressive.
Ruby philosophy: "Ruby is designed to make programmers happy." — Matz
1. Ruby Basics & Syntax
Variables, Types, and String Interpolation
Ruby is dynamically typed with no type declarations. It has local, instance, class, and global variables, differentiated by prefix symbols.
# Local variables (lowercase or underscore)
name = "Alice"
age = 30
pi = 3.14159
# String interpolation
puts "Hello, #{name}! You are #{age} years old."
# Multi-line strings (heredoc)
bio = <<~TEXT
Name: #{name}
Age: #{age}
Loves Ruby!
TEXT
puts bio
# Symbols (immutable, reusable identifiers)
status = :active
direction = :north
# Conditionals
score = 85
grade = if score >= 90
"A"
elsif score >= 75
"B"
else
"C"
end
puts "Grade: #{grade}"
# One-line conditional
puts "Adult" if age >= 18
puts "Retry" unless score == 100
# Case/when (Ruby's switch)
case score
when 90..100 then puts "Excellent"
when 75..89 then puts "Good"
when 60..74 then puts "Average"
else puts "Needs improvement"
endLoops and Iterators
Ruby has traditional loops but favors iterators with blocks. Methods like times, upto, each, and loop are idiomatic Ruby.
# times iterator
5.times { |i| puts "Iteration #{i}" }
# upto / downto
1.upto(5) { |n| print "#{n} " }
5.downto(1) { |n| print "#{n} " }
# loop with break
count = 0
loop do
count += 1
break if count >= 5
puts "Count: #{count}"
end
# while
n = 1
while n <= 10
puts n if n.odd?
n += 1
end
# until (opposite of while)
x = 0
until x >= 3
puts "x = #{x}"
x += 1
end
# for..in (less common, each preferred)
for i in 1..5
puts i
end2. Arrays, Hashes & Ranges
Arrays and Hashes
Ruby arrays are ordered, dynamic collections. Hashes are key-value pairs, commonly using symbols as keys. Both support rich built-in methods.
# Arrays
fruits = ["apple", "banana", "mango"]
numbers = [1, 2, 3, 4, 5]
# Common array methods
fruits.push("orange") # Add to end
fruits.unshift("grape") # Add to front
fruits.pop # Remove from end
fruits.first # First element
fruits.last # Last element
fruits.length # Number of elements
fruits.include?("mango") # true
# Functional methods
doubled = numbers.map { |n| n * 2 } # [2, 4, 6, 8, 10]
evens = numbers.select { |n| n.even? } # [2, 4]
total = numbers.reduce(0) { |sum, n| sum + n } # 15
sorted = [3, 1, 4, 1, 5].sort.uniq # [1, 3, 4, 5]
# Hashes
person = { name: "Alice", age: 25, city: "London" }
person[:email] = "alice@example.com" # Add key
puts person[:name] # Access value
person.each { |k, v| puts "#{k}: #{v}" }
# Hash methods
person.keys # [:name, :age, :city, :email]
person.values # ["Alice", 25, "London", ...]
person.has_key?(:age) # true
person.merge({ country: "UK" })
# Ranges
(1..10).to_a # [1, 2, ..., 10] (inclusive)
(1...10).to_a # [1, 2, ..., 9] (exclusive)
("a".."e").to_a # ["a", "b", "c", "d", "e"]3. Object-Oriented Ruby
Classes and Inheritance
Everything in Ruby is an object. Classes define object blueprints. attr_accessor, attr_reader, and attr_writer generate getter/setter methods automatically.
class Animal
attr_accessor :name, :sound
attr_reader :legs
def initialize(name, sound, legs)
@name = name # instance variable
@sound = sound
@legs = legs
end
def speak
"#{@name} says #{@sound}!"
end
def to_s
"#{@name} (#{@legs} legs)"
end
end
class Dog < Animal
def initialize(name)
super(name, "Woof", 4)
@tricks = []
end
def learn_trick(trick)
@tricks << trick
puts "#{@name} learned #{trick}!"
end
def show_tricks
puts "#{@name} knows: #{@tricks.join(', ')}"
end
def speak
super + " *wags tail*"
end
end
dog = Dog.new("Rex")
puts dog.speak
dog.learn_trick("sit")
dog.learn_trick("shake")
dog.show_tricks
puts dog # calls to_s4. Blocks, Procs & Lambdas
Ruby's Functional Building Blocks
Blocks are anonymous chunks of code passed to methods. Procs and lambdas are reusable, storable blocks. They're fundamental to Ruby's functional style.
# Blocks with do..end or {}
[1, 2, 3].each do |n|
puts n * 10
end
[1, 2, 3].each { |n| puts n * 10 }
# yield — invoke a block inside a method
def with_logging(label)
puts "Starting: #{label}"
result = yield # runs the block
puts "Done: #{label} => #{result}"
result
end
with_logging("math") { 2 + 2 }
# Proc — stored block
square = Proc.new { |x| x ** 2 }
puts square.call(5) # 25
double = proc { |x| x * 2 }
puts double.call(7) # 14
# Lambda — stricter proc
multiply = lambda { |x, y| x * y }
puts multiply.call(3, 4) # 12
# Stabby lambda syntax
greet = ->(name) { "Hello, #{name}!" }
puts greet.call("World")
# Method objects
puts [1, -2, 3, -4].map(&method(:puts))
puts [-3, -1, 2, 4].select(&:positive?)5. Modules & Mixins
Modules as Mixins
Ruby doesn't support multiple inheritance, but modules (mixins) allow sharing methods across unrelated classes. include adds instance methods; extend adds class methods.
module Serializable
def to_json
vars = instance_variables.map do |var|
key = var.to_s.delete("@")
value = instance_variable_get(var)
""#{key}": "#{value}""
end
"{ #{vars.join(', ')} }"
end
end
module Timestampable
def created_at
@created_at ||= Time.now
end
end
class User
include Serializable
include Timestampable
attr_accessor :name, :email
def initialize(name, email)
@name = name
@email = email
end
end
class Post
include Serializable
attr_accessor :title, :body
def initialize(title, body)
@title = title
@body = body
end
end
user = User.new("Alice", "alice@ruby.io")
post = Post.new("Hello Ruby", "Ruby is great!")
puts user.to_json
puts post.to_json6. Ruby on Rails Overview
Rails MVC and ActiveRecord
Rails is a full-stack MVC web framework. ActiveRecord is its ORM — it maps classes to database tables with a rich query interface. Migrations manage schema changes.
# Model — app/models/user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_one :profile
validates :name, presence: true, length: { minimum: 2 }
validates :email, presence: true, uniqueness: true,
format: { with: URI::MailTo::EMAIL_REGEXP }
scope :active, -> { where(active: true) }
scope :admins, -> { where(role: 'admin') }
def full_name
"#{first_name} #{last_name}"
end
end
# ActiveRecord queries
User.all
User.find(1)
User.find_by(email: "alice@example.com")
User.where(active: true).order(:created_at).limit(10)
User.active.admins
# Controller — app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
@users = User.active.order(:name)
render json: @users
end
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created
else
render json: @user.errors, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :email, :role)
end
endKeep Coding with Ruby!
Ruby's elegance and expressiveness make it one of the most enjoyable languages to write. Explore Rails, Sinatra, and the rich Ruby gem ecosystem.