Menu
Coddy logo textTech

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 icon

Challenge

Easy

Extend the menu loop with the "4" branch:

  1. print the prompt Title: and read it
  2. Use find to locate the book with that exact title
  3. If no match, print Not found.
  4. Otherwise, set book[:read] = true and print Marked 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!"
end

Try 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
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Logic & Flow