Checkpoint: OOP & Stdlib

This checkpoint ties together Ruby's object-oriented features and standard-library tools — inheritance, custom exceptions, dates, and serialization — into one realistic build challenge.

Learn Checkpoint: OOP & Stdlib in our free Ruby course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Review the recap, attempt the challenge before peeking, then test yourself with the quiz.

What This Checkpoint Covers

1️⃣ Recap: Inheritance, super & Pattern Matching

A subclass inherits its parent's behaviour and can override methods, calling super to reuse the parent's version. Constants live on the class, and case/in deconstructs data by shape.

2️⃣ Recap: Exceptions, Dates & JSON

Custom errors give failures a meaningful name, require 'date' brings calendar handling, and to_json serializes hashes for transport — the standard-library trio you'll reach for constantly.

3️⃣ Build Challenge: Shapes to JSON

Now combine it all: a class hierarchy with overridden area , a custom validation error, and JSON serialization of the whole collection. Try it yourself first — the solution is hidden below.

It calls the parent's method of the same name, forwarding the same arguments the current method received.

So a plain rescue catches it, while system-level Exception subclasses (like Ctrl-C) still propagate.

Give it a to_h (or to_json ) that returns only primitives — strings, numbers, arrays, and hashes.

It matches by structure (deconstruction). With no matching branch and no else , it raises NoMatchingPatternError .

require 'date' for Date/DateTime; Time is built in and needs no require.

Three test methods ran, making four assertions total (one test made two assertions) — and all passed.

Practice quiz

What does a bare super (no parentheses) do?

  • Passes no arguments to the parent
  • Calls a method named 'super'
  • Forwards the same arguments the current method received to the parent's method
  • Creates a new instance

Answer: Forwards the same arguments the current method received to the parent's method. Bare super forwards the exact arguments the current method received. super() passes none, and super(a, b) passes exactly those.

In the Circle subclass, what does super("circle") do?

  • Passes just the string 'circle' to Shape#initialize
  • Forwards radius to the parent
  • Skips the parent constructor
  • Raises an error

Answer: Passes just the string 'circle' to Shape#initialize. super("circle") deliberately passes one argument up to Shape#initialize, setting the name, regardless of Circle's own arguments.

Why raise NotImplementedError in the base Shape#area method?

  • To make Shape run faster
  • To return a default area of 0
  • To skip the subclass
  • To mark Shape as abstract so calling area on a raw Shape fails loudly

Answer: To mark Shape as abstract so calling area on a raw Shape fails loudly. It documents the contract 'every shape must define area' and fails clearly if a subclass forgets to override it.

Why should a custom exception inherit from StandardError rather than Exception?

  • StandardError is faster
  • A plain rescue catches StandardError, while Exception subclasses like Ctrl-C still propagate
  • Exception cannot be subclassed
  • StandardError prints a stack trace automatically

Answer: A plain rescue catches StandardError, while Exception subclasses like Ctrl-C still propagate. A bare rescue catches StandardError and its descendants but not system-level Exceptions like SystemExit or Interrupt.

How do you make a custom object JSON-serializable?

  • Give it a to_h (or to_json) that returns only primitives
  • Add a to_s method
  • Inherit from JSON::Object
  • Nothing; JSON handles any object

Answer: Give it a to_h (or to_json) that returns only primitives. JSON only understands strings, numbers, booleans, null, arrays, and hashes, so convert the object via to_h returning those primitives.

What does shapes.map(&:to_h) produce before JSON.pretty_generate?

  • A single hash
  • A JSON string
  • A list of hashes, one per shape
  • An array of strings

Answer: A list of hashes, one per shape. map(&:to_h) calls to_h on each shape, turning the array of objects into an array of hashes ready for JSON.

What does case/in (pattern matching) compare with?

  • === case-equality
  • Structure, by deconstructing the value
  • Object identity
  • String equality only

Answer: Structure, by deconstructing the value. case/in matches by structure (deconstruction), binding variables like { status: :ok, code: } from the shape of the data.

Which error fires when case/in has no matching branch and no else?

  • NoMethodError
  • ArgumentError
  • StandardError
  • NoMatchingPatternError

Answer: NoMatchingPatternError. With no matching in-clause and no else, case/in raises NoMatchingPatternError.

Which require do you need for Date, and what about Time?

  • require 'date' for both
  • require 'date' for Date/DateTime; Time is built in and needs no require
  • require 'time' for both
  • Neither needs a require

Answer: require 'date' for Date/DateTime; Time is built in and needs no require. Date and DateTime live in the date library (require 'date'), but Time is part of core Ruby.

A Minitest summary reads '3 runs, 4 assertions'. What does it tell you?

  • 3 files were loaded
  • Four tests failed
  • Three test methods ran, making four assertions total
  • Three assertions passed and one failed

Answer: Three test methods ran, making four assertions total. Runs counts test methods (3) and assertions counts total checks (4) — one test made two assertions.