Ruby Programming Language Explained — Complete Beginner's Guide
Ruby is a dynamically typed, object-oriented programming language focused on developer happiness and productivity, where everything — including numbers and classes — is an object.
What You’ll Learn
- The “everything is an object” philosophy
- Blocks, procs, and lambdas for closures
- Metaprogramming — code that writes code
- Gems and RubyGems package management
- Ruby on Rails overview
Why It Matters
Ruby powers thousands of web applications through the Ruby on Rails framework — GitHub, Shopify, Airbnb, and Basecamp were all built with Rails. DodaZIP’s automation scripts use Ruby for its expressive syntax and powerful metaprogramming capabilities. Ruby’s philosophy of “optimizing for programmer happiness” makes it one of the most enjoyable languages to write, especially compared to the verbosity of Java.
Learning Path
flowchart LR
A[Ruby Basics<br/>You are here] --> B[Objects & Methods]
B --> C[Blocks & Procs]
C --> D[Metaprogramming]
D --> E[Build a Rails App]
Everything Is an Object
In Ruby, even basic types like integers and strings are objects with methods.
# Integers are objects
puts 42.class # Integer
puts 42.even? # true
puts 42.to_s # "42"
puts 42.times { print "A" } # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
# Methods on objects
puts "hello".upcase # HELLO
puts "hello".reverse # olleh
puts [1, 2, 3].length # 3
puts [1, 2, 3].sum # 6
# Classes are objects too
puts String.class # Class
puts Class.class # ClassBlocks, Procs, and Lambdas
Blocks are anonymous code blocks. Procs and lambdas are reusable blocks.
# Block — used with iterators
[1, 2, 3].each do |n|
puts n * 2
end
# 2
# 4
# 6
# Block with curly braces (single line)
result = [1, 2, 3, 4, 5].select { |n| n.even? }
puts result.inspect # [2, 4]
# Proc — reusable block
double = Proc.new { |x| x * 2 }
puts [1, 2, 3].map(&double).inspect # [2, 4, 6]
# Lambda — stricter proc
greet = ->(name) { "Hello, #{name}!" }
puts greet.call("Alice") # Hello, Alice!
# Key difference: lambda checks arity, proc does not
add = lambda { |a, b| a + b }
puts add.call(1, 2) # 3
# puts add.call(1) # ArgumentError (wrong number of arguments)Metaprogramming
Ruby can create methods, classes, and behavior dynamically at runtime.
# Dynamic method definition
class Animal
%w[dog cat cow].each do |animal|
define_method("#{animal}_sound") do
case animal
when "dog" then "Woof!"
when "cat" then "Meow!"
when "cow" then "Moo!"
end
end
end
end
animal = Animal.new
puts animal.dog_sound # Woof!
puts animal.cat_sound # Meow!
puts animal.cow_sound # Moo!
# method_missing — catch-all for undefined methods
class Ghost
def method_missing(name, *args)
puts "Called #{name} with #{args.inspect}"
end
end
ghost = Ghost.new
ghost.hello("world") # Called hello with ["world"]Gems and RubyGems
RubyGems is Ruby’s package manager. A gem is a packaged Ruby library.
gem install sinatra
# Fetching sinatra-3.1.0.gem
# Successfully installed sinatra-3.1.0# Gemfile for Bundler
source "https://rubygems.org"
gem "sinatra", "~> 3.1"
gem "puma", "~> 6.0"
gem "json"
group :development do
gem "pry"
endbundle install
# Installed all gems from GemfileRuby on Rails Overview
Rails is a full-stack web framework built on Ruby’s “convention over configuration” philosophy.
# Model — interacts with database
class Article < ApplicationRecord
validates :title, presence: true
validates :body, length: { minimum: 10 }
belongs_to :author
has_many :comments, dependent: :destroy
end
# Controller — handles requests
class ArticlesController < ApplicationController
def index
@articles = Article.all.order(created_at: :desc)
end
def show
@article = Article.find(params[:id])
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render :new
end
end
private
def article_params
params.require(:article).permit(:title, :body)
end
endRails generates scaffolding with a single command: rails generate scaffold Article title:string body:text.
Common Mistakes
1. Confusing = with == in conditionals
if x = 5 # always true — assigns 5 to x!
if x == 5 # correct comparison2. Mutating objects when you intended to return a new one
str = "hello"
str.upcase! # ! mutates in place
str.upcase # without ! returns a new string3. Not understanding puts vs return
puts prints to stdout; it doesn’t return the value. The last expression in a method is returned automatically.
4. Creating overly complex metaprogramming
With great power comes great responsibility. Metaprogramming can make code hard to debug. Use it judiciously.
5. Symbol vs String confusion
:name == "name" # false — symbols are not stringsSymbols are immutable, interned identifiers. Strings are mutable text. Use symbols for keys, strings for data.
6. Using for loops instead of enumerables
Ruby prefers each, map, select over for. Enumerables are more idiomatic and chainable.
Practice Questions
What does “everything is an object” mean in Ruby? Every value — numbers, strings, classes, even
trueandnil— is an instance of some class and responds to methods.What’s the difference between a Proc and a Lambda? Lambdas check argument count (like methods); Procs don’t.
returnin a lambda returns from the lambda;returnin a proc returns from the enclosing method.What is a Gem? A packaged Ruby library distributed through RubyGems. Gems contain code, metadata, and dependencies.
What does
attr_accessor :namedo? Creates getter and setter methods for the@nameinstance variable:def name; @name; endanddef name=(val); @name = val; end.What is convention over configuration? Rails’ philosophy of providing sensible defaults so developers write less configuration code. File names determine class names, table names, and routes.
Challenge: Write a Ruby script using metaprogramming to track method calls — log every method invocation on an object with timestamp and arguments.
Mini Project — Log File Analyzer
Build a Ruby script that analyzes server log files using enumerables and blocks.
class LogAnalyzer
def initialize(filepath)
@filepath = filepath
end
def analyze
entries = File.readlines(@filepath)
total_requests = entries.length
status_counts = entries.map { |e| e.split[8] }.tally
ip_counts = entries.map { |e| e.split[0] }.tally
path_counts = entries.map { |e| e.split[6] }.tally
puts "=== Log Analysis ==="
puts "Total requests: #{total_requests}"
puts
puts "Top 5 Status Codes:"
status_counts.sort_by { |_, v| -v }.first(5).each do |code, count|
puts " #{code}: #{count}"
end
puts "\nTop 5 IP Addresses:"
ip_counts.sort_by { |_, v| -v }.first(5).each do |ip, count|
puts " #{ip}: #{count}"
end
puts "\nTop 10 Paths:"
path_counts.sort_by { |_, v| -v }.first(10).each do |path, count|
puts " #{path}: #{count}"
end
end
end
if ARGV.empty?
puts "Usage: ruby log_analyzer.rb <logfile>"
exit 1
end
analyzer = LogAnalyzer.new(ARGV[0])
analyzer.analyzeFAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro