Ruby is the programming language we use on the backend. This lesson takes you from your first script to classes, blocks and custom errors โ the working vocabulary for everything that follows.
Important
Work on this lesson in
teachermode.
Learning goals
- You can write and run a small Ruby program that reads input (e.g. arguments or a file) and prints output.
- You can work with Ruby's core data types โ strings, symbols, numbers, booleans,
nil, arrays and hashes โ with their everyday collection methods (e.g.map,select), and explain what "everything is an object" means. - You write Ruby in the canonical style: two-space indentation,
snake_casenames, predicate methods ending in?, dangerous methods ending in!, terse APIs. - You can define methods with positional and keyword arguments, and explain when a method returns a value without
return. - You can write classes with a constructor, attribute accessors, inheritance and
super, and explain the difference between class methods and instance methods. - You can use modules both as mixins and as namespaces.
- You can write methods that take a block, and explain how blocks, procs and lambdas differ.
- You can raise and rescue errors, including your own error classes.
- You can reopen an existing class to add behavior (monkey patching), and explain why that should be rare.
Resources
Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.
Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.
Start here
- ๐ Ruby from other languages Show archive.org snapshot โ the differences that bite when you come from Java, Python or C
- ๐ Learn X in Y minutes: Ruby Show archive.org snapshot โ the whole syntax on one page
Pick one tutorial
- ๐ The Odin Project: Ruby Show archive.org snapshot โ text with exercises; do "Basic Ruby", "OOP Basics" and "Advanced Ruby: Blocks"
- ๐ฎ Codecademy: Learn Ruby Show archive.org snapshot โ interactive course in the browser
- ๐ I Love Ruby Show archive.org snapshot โ free book; chapters 1โ15, 17โ22 and 24โ25 are relevant for now
- โถ๏ธ freeCodeCamp: Ruby full course Show archive.org snapshot โ 4-hour video; from 2018, but the basics haven't changed
For specific goals
- ๐ Ruby Style Guide Show archive.org snapshot โ naming and formatting conventions
- ๐ Exceptions Show archive.org snapshot and the Exception class hierarchy Show archive.org snapshot โ official Ruby docs
- ๐ Proc: lambda vs. non-lambda semantics Show archive.org snapshot โ blocks, procs and lambdas, official Ruby docs
- ๐ The Case Against Monkey Patching Show archive.org snapshot โ why reopening classes should be rare
For detailed information on a Ruby class or method, see the card Asking your agent about APIs and libraries.
Exercises
Create a separate directory for each exercise, inside the exercises repository you set up on your first day.
Counting words
Write a small ruby programm count_words.rb that accepts a filename, counts the number of words, lines and paragraphs, and outputs the result.
For example:
$ ruby count_words.rb test.txt
test.txt has 123 words
test.txt has 13 lines
test.txt has 4 paragraphs
Hint
- Find out about
ARGV.- Look up
Filein one of the references above.- You can create random text on randomtextgenerator.com Show archive.org snapshot .
- Learn about regular expressions Show archive.org snapshot .
Address search
Write a Contact class that models an address book entry.
It should offer an API like this:
contact = Contact.new(first_name: 'Anna', last_name: 'Muster', street: 'Foo Avenue 77')
contact.first_name # => 'Anna'
contact.last_name # => 'Muster'
A Contact object should be able to store:
- First name
- Last name
- Street
- Postal code
- City
- Phone numbers
All fields are optional, except for #last_name. If we try to instantiate a contact without a last name, the constructor raises an error:
Contact.new(first_name: 'Anna') # raises ArgumentError
Now build an AddressBook class that can store a list of contacts in memory:
addresses = AddressBook.new
addresses.add Contact.new(first_name: 'Frederik', last_name: 'Foo')
addresses.add Contact.new(first_name: 'Berta', last_name: 'Beispiel', phone: '556677')
addresses.add Contact.new(first_name: 'Anna', last_name: 'Muster', street: 'Foo Avenue 77')
addresses.size # => 3
Now write a method AddressBook#search that takes a query string and returns an array of Contact objects that match the given word in any of their properties (name, street, city, etc.):
results = addresses.search('foo') # returns an Array of "Frederik" and "Anna" contacts
results.size # => 2
results[0].class # => Contact
results[0].first_name # => "Frederik"
results[1].street # => "Foo Avenue 77"
Hint
You can convert any object to a string by calling
#to_son it.
The matching should be case-insensitive Show archive.org snapshot .
Also when the query string contains more than one word, it returns contacts that match all of the words in any property:
results = addresses.search('77 berta')
results.size # => 1
results[0].first_name # => "Berta"
Errors
Change the AddressBook class so the #add method throws a DuplicateContact error when the user tries to add a contact that already exist. We consider two contacts to be duplicates if they have the same first and last name.
Hint
Create a custom error class Show archive.org snapshot that inherits from
StandardError.
Blocks and monkey patches
Give Array a new method #random_each. The method should iterate through the array elements in random order and call the given block for each iteration.
For example, the following should work:
[1, 2, 3, 4, 5].random_each do |value|
puts value * -1
end
And get an output like this:
-4
-2
-1
-5
-3
Hint
- Research "monkey patching": how to reopen a class, and why it should be rare Show archive.org snapshot .
- Research Ruby's
yieldkeyword
Feedback round
When all four exercises run, ask the agent for feedback on your Ruby style. Expect pointers, not corrections: it will show you where to look and what concept applies, and you make the changes yourself. Fix what you learn and commit again.