Mark As Read
Part of the Logic & Flow section of Coddy's Ruby journey — lesson 32 of 56.
Add the final option, 4. Mark As Read. The user types an exact title and the program flips that book's :read key from false to true.
To find the book, use find: it returns the first element matching the block, or nil when nothing matches:
book = library.find { |b| b[:title] == query }If book is nil, report that no book was found. Otherwise, mutate it in place, Ruby hashes share their identity inside the array, so updating book[:read] updates the entry stored in library too.
Challenge
EasyExtend the menu loop with the "4" branch:
printthe promptTitle:and read it- Use
findto locate the book with that exact title - If no match, print
Not found. - Otherwise, set
book[:read] = trueand printMarked as read!
Keep all earlier branches working.
For inputs that add The Hobbit, mark it read, then exit, the marking block prints:
Choose an option: Title: Marked as read!Cheat sheet
Use find to locate the first matching element in an array (returns nil if not found):
book = library.find { |b| b[:title] == query }Since hashes share identity inside arrays, mutating the found object updates the original entry:
if book.nil?
puts "Not found."
else
book[:read] = true
puts "Marked as read!"
endTry it yourself
library = []
loop do
puts "--- Library Manager ---"
puts "1. Add Book"
puts "2. Search By Title"
puts "3. Filter By Genre"
puts "4. Mark As Read"
puts "5. Exit"
print "Choose an option: "
choice = gets.chomp
if choice == "5"
puts "Goodbye!"
break
elsif choice == "1"
print "Title: "
title = gets.chomp
print "Author: "
author = gets.chomp
print "Genre: "
genre = gets.chomp
library.push({ title: title, author: author, genre: genre, read: false })
puts "Book added!"
elsif choice == "2"
print "Search title: "
query = gets.chomp
matches = library.select { |b| b[:title].downcase.include?(query.downcase) }
if matches.empty?
puts "No matches."
else
matches.each { |b| puts "#{b[:title]} by #{b[:author]}" }
end
elsif choice == "3"
print "Genre: "
genre = gets.chomp
matches = library.select { |b| b[:genre] == genre }
matches.each { |b| puts "#{b[:title]} by #{b[:author]}" }
puts "Total: #{matches.length}"
end
# TODO: handle choice == "4", find by exact title,
# set book[:read] = true, print "Marked as read!" or "Not found."
end
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Logic & Flow
1Strings In Depth
String Methods OverviewString InterpolationIterating Over StringsSplit and JoinRecap - String Weaver4Blocks, Procs & Lambdas
What is a Block?do..end vs BracesThe yield KeywordBlock ParametersProcs and LambdasRecap - Custom Iterator7Hashes Part 2
Hash.new with DefaultsIterating HashesNested HashesMerging and TransformingRecap - Frequency Counter10Project - Student Records
Project OverviewAdd Student5Enumerable Powerhouse
Select and RejectChaining MapReduce / Injectcount, all?, any?, none?group_by and partitionsort_by, min_by, max_byRecap - Data Pipeline8Advanced Decision Making
Case with Classes & RegexMulti-value whenTernary OperatorInline if / unlessRecap - Grade Classifier