Checkpoint: Ruby Basics
Reviewed & published by Brayan K
A checkpoint is a consolidation lesson that pulls together everything you've learned so far — operators, truthiness, loops, case/when, string methods, enumerable, Struct, and Set — into one realistic build challenge that proves the pieces fit together.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
There's a recap, a multi-step program to build (with a full worked solution to compare against), and a short quiz to confirm the ideas have stuck.
What You've Learned So Far
- Operators & expressions: arithmetic, <=>, &&/||, ternary, ranges
- Truthiness: only nil and false are falsy (0 and "" are truthy)
- Loops: while/until, loop do, times/upto/downto, next/break
- case/when: matching with === on values, ranges, classes, regexes
- String methods: interpolation, split/join, gsub, format, bang methods
- Advanced Enumerable: reduce, group_by, tally, sort_by, each_with_object
- Struct & OpenStruct: one-line value objects, keyword_init, Data.define
- Sets: uniqueness, fast include?, union/intersection/difference
🛠️ Build Challenge: A Word-Frequency Report
Your mission is a single script that reads a sentence and prints a tidy report: a bar chart of word counts (built from a Struct and tally), the repeated words (via a Set), and a case/when verdict on the vocabulary size. Start from the brief below.
# 🎯 BUILD CHALLENGE — a word-frequency report.
# Save as report.rb and run with: ruby report.rb
#
# Put your new skills together. Given:
# text = "the rain in spain falls mainly on the plain the rain"
#
# 1) Lowercase and split the text into words. (String methods)
# 2) Count each word with tally. (Advanced Enumerable)
# 3) Wrap each word+count in a Struct WordStat, (Struct)
# sorted by count DESC then word ASC (sort_by).
# 4) Print " <word> <stars> (<n> time/times)" for each,
# using "*" * count and the right singular/plural via a ternary.
# 5) Collect the words that appear more than once into a Set,
# and print them sorted. (Sets)
# 6) Print the distinct-word count with a case/when verdict:
# 0..3 -> "tiny", 4..8 -> "small", else "rich". (case/when)
#
# Expected output is shown below. Try it yourself first,
# then open "Show solution" to compare.
# your code hereOne clean way to solve it — note how each numbered step maps to a lesson you've completed:
Touched lessons: String methods (downcase/split/ljust), Enumerable (tally/map/sort_by/select), Struct (WordStat), Operators (ternary, unary minus for the sort key), Sets (to_set), and case/when (the verdict).
📝 Checkpoint Quiz
Answer each in your head (or out loud), then expand to check. If you miss one, the parenthetical points you to the lesson to review.
Only nil and false. Everything else — including 0, "", and [] — is truthy, so if 0 runs its block.
It's 2 — integer division truncates. For 2.333… make a side a Float: 7.0 / 3 or 7.fdiv(3).
It uses case-equality: when_value === subject. That's why ranges (80..89), classes (Integer), and regexes all work as when targets.
map returns a new array the same size, transforming each element. reduce collapses the whole collection into a single value via an accumulator, e.g. [1,2,3].reduce(:+) is 6.
A Set rejects duplicates and uses hashing, so include? is roughly O(1). On an Array, include? scans every element (O(n)), which is slow inside loops.
"ab" * 3 is "ababab" (string repetition). gsub replaces every match while sub replaces only the first.
Pro Tips for the Road Ahead
- 💡 Type the examples: retyping (not copy-pasting) cements syntax far faster.
- 💡 Reach for the right tool: tally for counts, Set for uniqueness, Struct for shape.
- 💡 Read errors closely: undefined method ... for nil almost always means an unexpected nil upstream.
If You Got Stuck, Revisit
- Struggled with tally/sort_by? → Advanced Enumerable
- Unsure about the ternary or -s.count sort key? → Operators & Expressions
- Confused by the Struct shape? → Struct & OpenStruct
- Lost on to_set? → Sets
🎉 Checkpoint Complete!
- ✅ You combined operators, truthiness, loops, and case/when
- ✅ You wrangled text with String methods and summarized with Enumerable
- ✅ You modelled data with a Struct and used a Set for uniqueness
- ✅ You built and ran a complete word-frequency report
- ✅ You self-checked with the quiz and know where to review
Practice quiz
Which values are FALSY in Ruby?
- nil, false, 0, and ""
- Only false
- Only nil and false
- nil, false, and []
Answer: Only nil and false. Only nil and false are falsy. Everything else, including 0, "", and [], is truthy, so 'if 0' runs its block.
What does 7 / 3 evaluate to in Ruby?
- 2
- 2.333
- 3
- 2.0
Answer: 2. Integer division truncates, so 7 / 3 is 2. For the decimal, make a side a Float: 7.0 / 3 or 7.fdiv(3).
How do you get the decimal result of dividing 7 by 3?
- 7 / 3
- 7 % 3
- 7.div(3)
- 7.0 / 3 or 7.fdiv(3)
Answer: 7.0 / 3 or 7.fdiv(3). Make one operand a Float (7.0 / 3) or use 7.fdiv(3) to force floating-point division and get 2.333...
What does a 'when' clause actually compare with under the hood?
- == (equality)
- === (case-equality), i.e. when_value === subject
- eql?
- equal?
Answer: === (case-equality), i.e. when_value === subject. case/when uses ===, so ranges (80..89), classes (Integer), and regexes all work as when targets.
What is the difference between map and reduce?
- map returns a same-size array; reduce collapses to one value
- They are identical
- map collapses to one value; reduce transforms each element
- Both return a single number
Answer: map returns a same-size array; reduce collapses to one value. map transforms each element into a new same-size array; reduce folds the collection into a single value, e.g. [1,2,3].reduce(:+) is 6.
Why pick a Set over an Array for membership checks?
- Sets preserve insertion order
- Arrays cannot use include?
- Set rejects duplicates and uses hashing, so include? is roughly O(1)
- Sets are always smaller
Answer: Set rejects duplicates and uses hashing, so include? is roughly O(1). A Set hashes its elements, so include? is about O(1). On an Array, include? scans every element (O(n)).
What does "ab" * 3 produce?
- "ab3"
- "ababab"
- "ab ab ab"
- An error
Answer: "ababab". String * repeats the string, so "ab" * 3 is "ababab". The challenge uses "*" * count to draw a bar chart.
What is the difference between gsub and sub on a String?
- gsub replaces only the first match
- They are identical
- sub returns an array
- gsub replaces EVERY match; sub replaces only the FIRST
Answer: gsub replaces EVERY match; sub replaces only the FIRST. gsub (global sub) replaces every match, while sub replaces only the first occurrence.
In the build challenge, which Enumerable method counts how many times each word appears?
- group_by
- tally
- reduce
- sort_by
Answer: tally. tally returns a hash mapping each element to its count, e.g. words.tally turns the word list into word => count.
How do you sort the WordStat list by count DESC then word ASC with sort_by?
- sort_by { |s| [s.count, s.word] }
- sort_by { |s| s.count }.reverse
- sort_by { |s| [-s.count, s.word] }
- sort_by { |s| [s.word, s.count] }
Answer: sort_by { |s| [-s.count, s.word] }. Negating the count (-s.count) sorts it descending while word stays ascending, all in one array sort key.
Continue this course
- Previous: Sets
- Next: Inheritance & super — Subclassing, super, method overriding, and protected/private
- Quick reference: Ruby cheat sheet
Frequently asked questions
What should I be able to do after this checkpoint?
By now you should be comfortable combining the Ruby basics fluently: doing arithmetic and comparisons with operators, reasoning about truthiness (remembering that only nil and false are falsy), looping with while/until and the numeric iterators, branching with case/when, transforming text with String methods, summarizing collections with Advanced Enumerable methods like tally and sort_by, modelling data with Struct, and using Set for uniqueness. The build challenge on this page deliberately weaves all of those together, which is exactly how real Ruby code reads.
I couldn't finish the build challenge — is that a problem?
Not at all. Checkpoints are for honest self-assessment, not grading. If a step stumped you, that's a precise signal of which lesson to revisit — for example, struggling with tally and sort_by points back to Advanced Enumerable, while confusion about the ternary points back to Operators. Re-read that one lesson, retype its examples, then return and finish the challenge. Building the muscle memory by typing real code beats reading the solution.
Why does the report combine a Struct and a Set in one script?
Because real programs rarely use a single feature in isolation. The Struct gives each report line a clean, named shape (word and count with a little behaviour), while the Set answers the membership question 'which words repeat?' efficiently and without duplicates. Seeing them cooperate — alongside tally for counting, sort_by for ordering, and case/when for the verdict — is the whole point of a checkpoint: proving the pieces fit together.
What comes after the Ruby basics?
Next you move into object-oriented Ruby in depth, starting with Inheritance & super, where classes build on one another and reuse behaviour. The collection, string, and control-flow skills you've consolidated here are the foundation everything else stands on, so the time you spent on this checkpoint pays off directly in the classes-and-objects lessons ahead.