Written by James Britt
Technically reviewed by Jim Freeze · Reviewed 3 September 2026
If you learn best by taking working code apart, this collection of Ruby code examples is designed for you. It starts with small expressions, then moves through collections, methods, classes, files, JSON, regular expressions, and a complete mini-project. Every snippet is self-contained. Copy one into a file such as example.rb , then run it from a terminal with ruby example.rb . Change the values and run it again: experimentation is usually the quickest way to make Ruby’s concise syntax feel natural.
Ruby Code Examples at a Glance
- Output, variables, and interpolation
- Arrays, hashes, and ranges
- Conditions and loops
- Mapping, filtering, and reducing
- Methods, classes, and modules
- Errors, files, JSON, and regular expressions
- A complete word-frequency program
1. Print Text and Store a Value
puts prints a value followed by a newline. Ruby variables do not need a type declaration; the object assigned to the name determines what operations are available. The #{…} sections are string interpolation. Ruby evaluates each expression and inserts its result into a double-quoted string. Single-quoted strings do not interpolate values.
language = "Ruby"
year = 1995
puts "Learning #{language}"
puts "Ruby first appeared in #{year}."
2. Work With Numbers
In addition to being able to use common mathematical operations in your code, Ruby also has some rules that govern how they work. When dividing one number by another, if both numbers are integers then the result is an integer. So, you will need to include a decimal value for a result with decimals. The underscore character may be used to make large values easier to read: for example, 1_000_000 and 1000000 have the same value. Try this using whole-number values and decimal values to see how each operand’s data type determines the result of division.
subtotal = 24.50
quantity = 3
discount = 5
total = (subtotal * quantity) - discount
average = total / quantity
puts total.round(2) # 68.5
puts average.round(2) # 22.83
3. Transform a String
Strings have standard methods for normal cleanup and formatting. This example has strip remove any leading or trailing white space, split create a list of individual words, map apply capitalize to each word, and join reconstruct the last string. When something doesn’t behave as expected with a chain, either print its value during execution or inspect the intermediate results. It is common, when things don’t seem to be working correctly, to look at what was produced by split before proceeding.
raw_title = " ruby code examples "
clean_title = raw_title.strip.split.map(&:capitalize).join(" ")
puts clean_title # Ruby Code Examples
4. Add, Remove, and Read Array Items
An array is an ordered collection. Indexes begin at zero, while a negative index counts backwards from the end. The shovel operator, << , appends an item to the array. Methods such as first , last , include? , and length make routine checks readable. Test the array with duplicate names and with no items at all. Notice that delete changes the existing array, while reader methods simply return information about its current contents.
frameworks = ["Rails", "Sinatra"]
frameworks << "Hanami"
frameworks.delete("Sinatra")
puts frameworks.first # Rails
puts frameworks[-1] # Hanami
puts frameworks.length # 2
5. Store Named Values in a Hash
Hashes hold values by key. The key can be one of several types of object in Ruby; symbols are simply a common type used as names within the code. Using square brackets retrieves the value for an existing key or assigns a new value. When iterating, a two-parameter block receives the current key and its associated value. Compare how a lookup of a non-existent key returns nil with how fetch can return a default you provide. Depending on what should happen when an entry is missing, either behaviour may serve well.
book = {
title: "The Ruby Way",
pages: 816,
available: true
}
puts book[:title]
book[:pages] = 820
book[:format] = "paperback"
book.each do |key, value|
puts "#{key}: #{value}"
end
6. Generate Values From a Range
Two dots are used to define an inclusive range. Three dots define a range where the final value is excluded. Ranges can represent sequences, select slices, or test whether a value falls between two endpoints. When defining one, it is easy to make an off-by-one error by choosing the wrong form for the problem being solved.
inclusive = (1..5).to_a
exclusive = (1...5).to_a
puts inclusive.inspect # [1, 2, 3, 4, 5]
puts exclusive.inspect # [1, 2, 3, 4]
puts (1..10).include?(7) # true
7. Make a Decision With if, elsif, and else
Ruby treats only false and nil as falsey. Everything else, including 0 and an empty string, is truthy. A short condition can also follow the action: puts “Take a coat” if temperature < 10 . Run the condition with values on either side of every boundary. Testing the exact cutoff as well as nearby values is a simple habit that catches faulty comparison operators early.
temperature = 18
if temperature >= 25
puts "Warm"
elsif temperature >= 15
puts "Mild"
else
puts "Cool"
end
8. Match Several Possibilities With case
A case expression generally reads better than many equality checks chained in succession; it also allows for direct assignment of the result. Because Ruby employs case-equality behaviour rather than simply comparing values on a branch-by-branch basis, range branches can keep related status codes together while still allowing an individual branch when you need a unique message for one status.
status_code = 404
message = case status_code
when 200..299 then "Success"
when 400 then "Bad request"
when 404 then "Not found"
when 500..599 then "Server error"
else "Unknown status"
end
puts message
9. Loop With each and each_with_index
Ruby programs usually iterate over a collection instead of maintaining a counter manually. The block between do and end runs once per item. each_with_index supplies both the item and its zero-based position. Remove the index adjustment and compare the output. The collection position begins at zero, but numbered text intended for readers will usually begin at one.
topics = ["strings", "arrays", "hashes"]
topics.each_with_index do |topic, index|
puts "#{index + 1}. #{topic.capitalize}"
end
10. Build a New Array With map
Use map when all input items will be used to create one output item. Map creates an entirely new collection. As you see in the example, prices_with_vat is a variable and not a method. After assigning prices_with_vat, the old prices remain unchanged in the original array. This is because the returned list of numbers from map was created as a new array through a separate assignment.
prices = [8.00, 12.50, 20.00]
prices_with_vat = prices.map do |price|
(price * 1.20).round(2)
end
p prices_with_vat # [9.6, 15.0, 24.0]
11. Filter Items With select and reject
select keeps items for which the block is truthy. reject does the opposite. Replace even? with another predicate and watch which values survive. Thinking of select as ‘keep matching items’ and reject as ‘discard matching items’ makes the pair easier to remember. Work slowly enough to connect the output with the specific expression that produced it.
numbers = [3, 8, 11, 14, 19, 22]
even_numbers = numbers.select(&:even?)
small_numbers = numbers.reject { |number| number >= 10 }
p even_numbers # [8, 14, 22]
p small_numbers # [3, 8]
12. Combine Values With reduce
reduce , also known as inject , carries an accumulated value through the collection. It is handy for totals and other single-result calculations. Change the starting accumulator and follow the sum after each iteration. The initial value matters because it becomes the first left-hand input supplied to the block. Work slowly enough to connect the output with the specific expression that produced it.
basket = { keyboard: 45.00, mouse: 20.00, cable: 6.50 }
total = basket.values.reduce(0) do |sum, price|
sum + price
end
puts format("£%.2f", total) # £71.50
13. Define a Method With Keyword Arguments
Methods package behaviour behind a useful name. Keyword arguments make calls easier to understand and allow defaults for optional settings. Ruby returns the last evaluated expression automatically, so an explicit return is unnecessary here. Call the method with keyword arguments in a different order. Their names, rather than their positions, identify the values, which makes a call with several options much easier to read.
def greeting(name:, formal: false)
formal ? "Good morning, #{name}." : "Hi, #{name}!"
end
puts greeting(name: "Mina")
puts greeting(name: "Mina", formal: true)
14. Handle a Missing Value Safely
The safe-navigation operator, &. , calls a method when the receiver is not nil . If it is nil , the expression returns nil instead of raising NoMethodError . Use safe navigation deliberately. If a missing object indicates a programming error, allowing an exception may be more useful than silently substituting a fallback.
user = { profile: nil }
name = user[:profile]&.fetch(:name, nil) || "Guest"
puts name # Guest
15. Create a Class
A class groups state and behaviour. The initialize method runs when new creates an instance, and attr_reader generates getter methods. Names beginning with @ are instance variables. Each BankAccount object keeps its own values. Attempt a negative deposit and read the resulting exception. Validation inside the object protects its state, regardless of which part of the program calls the method.
class BankAccount
attr_reader :owner, :balance
def initialize(owner, opening_balance = 0)
@owner = owner
@balance = opening_balance
end
def deposit(amount)
raise ArgumentError, "Amount must be positive" unless amount.positive?
@balance += amount
end
end
account = BankAccount.new("Ari", 100)
account.deposit(25)
puts account.balance # 125
16. Share Behaviour With a Module
A module can act as a namespace or provide reusable behaviour. Including it in a class adds its instance methods to objects of that class. Give the article name punctuation and repeated spaces. The module keeps slug-building behaviour in one place, ready for another class that exposes the same name method.
module Sluggable
def slug
name.downcase.strip.gsub(/[^a-z0-9]+/, "-").gsub(/^-|-$/, "")
end
end
class Article
include Sluggable
attr_reader :name
def initialize(name)
@name = name
end
end
article = Article.new("20 Useful Ruby Examples")
puts article.slug # 20-useful-ruby-examples
17. Rescue an Expected Exception
Rescue errors you know how to handle. Avoid catching every possible exception without a clear recovery path, because that can hide genuine bugs. Integer is preferable to to_i when invalid input must be detected: “hello”.to_i quietly returns zero, while Integer(“hello”) raises ArgumentError . Compare a valid zero with a word that cannot be converted. Returning nil for the latter lets the caller distinguish bad input from the perfectly legitimate number zero.
def integer_from(text)
Integer(text, 10)
rescue ArgumentError
nil
end
value = integer_from("42")
invalid = integer_from("forty-two")
p value # 42
p invalid # nil
18. Write and Read a Text File
File.write replaces a file’s contents, while File.read returns the entire file as a string. For large files, process lines incrementally instead. chomp removes the record separator at the end of each line. File.foreach is memory-friendly because it does not load the whole file at once. Use a disposable file while experimenting, and inspect it between runs. File operations affect the filesystem outside the Ruby process, so cleanup and path choice deserve deliberate attention.
path = "notes.txt"
File.write(path, "Arrays\nHashes\nMethods\n")
File.foreach(path).with_index(1) do |line, number|
puts "#{number}: #{line.chomp}"
end
19. Parse and Generate JSON
Ruby’s standard JSON library converts JSON objects to hashes and JSON arrays to Ruby arrays. Require it before use. Never treat JSON from an external source as trusted simply because it parsed successfully. Validate the fields and types your program expects. Remove symbolize_names and inspect the keys returned by the parser. JSON object names are strings by default, which changes how the resulting hash must be accessed.
require "json"
json = '{"name":"Ruby","dynamic":true}'
data = JSON.parse(json, symbolize_names: true)
puts data[:name]
output = JSON.generate(language: data[:name], topics: ["web", "scripts"])
puts output
20. Extract Data With a Regular Expression
A regular expression is useful when the input has a predictable textual pattern. Named captures make the extracted pieces self-explanatory. For structured formats such as JSON or CSV, use a parser rather than a regular expression. Regex is best reserved for genuinely textual patterns. Try a line that does not match and confirm that the conditional body is skipped. Real input often contains partial or malformed records, so a non-match should be an expected case.
log_line = "2026-09-02 level=ERROR request_id=abc123"
pattern = /level=(?<level>\w+) request_id=(?<request_id>\w+)/
if match = log_line.match(pattern)
puts match[:level]
puts match[:request_id]
end
Mini-Project: Count Word Frequency
This final example combines strings, arrays, hashes, iteration, sorting, and formatted output. It counts words without caring about capitalisation or basic punctuation. Hash.new(0) gives an unseen word an initial count of zero. The sort key uses the negative count to put frequent words first, then sorts words alphabetically when their counts match.
text = <<~TEXT
Ruby is expressive. Ruby is readable.
Readable code is easier to maintain.
TEXT
words = text.downcase.scan(/[a-z]+/)
counts = Hash.new(0)
words.each do |word|
counts[word] += 1
end
counts
.sort_by { |word, count| [-count, word] }
.each { |word, count| puts format("%-10s %d", word, count) }
How to Practise These Ruby Code Examples
The best next step is to combine two or three snippets into something personally useful: a file renamer, expense total, log analyser, or command-line checklist. A small program you actually want tends to teach more than a large example copied without modification. Use the examples as starting points rather than finished answers. Predict one change, run it, and explain the result in your own words before moving on to a larger exercise.
- Run each example unchanged so you know its starting behaviour.
- Predict what one small edit will do before running the program again.
- Turn fixed values into method arguments or terminal input.
- Add an edge case, such as an empty array, missing key, or invalid number.
- Read the exception rather than immediately deleting the line that caused it.
Official Ruby References
For deeper detail, use the official documentation for Ruby literals, methods, Enumerable, File, and JSON. The documentation describes the full API; the Ruby code examples above show how the pieces fit into everyday programs.
