Prohlížeč zdrojového kódu

docs/specs/examples.md

Náhled Zdrojový kód

Spec: Examples System

  • Status: active
  • Created: 2026-03-05
  • Related code: app/examples/, app/services/example_entry.rb, app/services/example_registry.rb, app/controllers/examples_controller.rb, app/views/examples/

Overview

The examples system lets visitors browse a curated set of Ruby code examples. Each example has metadata (title, description, tags) and optionally a source file displayed with syntax highlighting. Examples are grouped by tags and listed on an index page; clicking one opens a detail page. No database is involved — the filesystem is the single source of truth.

Behaviour

Storage

  • Each example lives in its own subdirectory under app/examples/<slug>/.
  • The subdirectory name is the example's slug (used in URLs).
  • Every example directory contains an example.yml (metadata) and an example.md content file. A .rb source file is optional.

Metadata (example.yml)

Required fields: title.
Optional fields: source_file, description (defaults to ""), tags (defaults to []), position (defaults to 999), scenarios.
- title and description are in Czech; option values stay in English.
- position controls listing order; lower numbers appear first. Examples without a position are sorted last.
- Tags are free-form strings in Czech used for filtering.
- Each scenario must define a boilerplate_file: an explicit filename (relative to the example directory) containing the runner snippet shown in the "Vyzkoušet" section.

Index page (/examples)

  • Lists all examples as cards showing title, description, and tags.
  • When tags exist, a tag filter bar appears above the grid with a "Vše" (all) link and one link per tag.
  • Filtering by tag shows only matching examples; the active filter is highlighted.
  • If no examples match, a Czech message is shown (different wording when filtering by tag vs. no examples at all).

Detail page (/examples/:slug)

  • Displays the example's title, tags, and rich content from example.md.
  • If source_file is present, the <!-- source --> placeholder in example.md is replaced with the syntax-highlighted source. Using <!-- source --> in an example without a source_file raises an error.
  • Examples without a source_file use example.md as the sole content driver, with code snippets embedded directly as fenced code blocks in the Markdown. This suits complex, multi-file topics ("case studies") where there is no single file to showcase.
  • If the example has scenarios, each <!-- scenario:N --> or <!-- scenarios --> placeholder is replaced with the scenario card — details covered in the scenario runner spec. Scenarios in a source-file-less example must be fully self-contained.
  • Unknown slugs raise a 404.

Registry

  • Examples are loaded at boot into an in-memory singleton (ExampleRegistry).
  • ExampleRegistry.all returns all entries sorted by position.
  • ExampleRegistry.find_by_slug(slug) returns an entry or nil.
  • ExampleRegistry.filter_by_tag(tag) returns matching entries sorted by position.
  • ExampleRegistry.tags returns all unique tags, sorted alphabetically.
  • ExampleRegistry.reload! rebuilds the singleton (used in tests and development).

Implementation Notes

  • app/examples/ is excluded from Zeitwerk autoloading (configured in config/application.rb) — example .rb files are loaded manually by ScenarioRunner inside an anonymous Module.
  • ExampleRegistry is a singleton class; the instance is memoized on first access via ExampleRegistry.instance.
  • ExampleEntry is a plain Ruby object (not ActiveRecord); Scenario and Input are inner Structs.
  • The registry reads all example.yml files at boot using Dir[examples_root.join("*", "example.yml")].
  • source_file is optional; ExampleEntry stores nil when the key is absent in example.yml. ExampleEntry#source_code returns nil in that case.
  • Source code is read from disk on each request via ExampleEntry#source_code.
  • boilerplate_file is resolved to an absolute path at parse time in build_scenarios; Scenario#boilerplate_code reads it on demand via File.read.
  • entry_class and entry_method are no longer part of ExampleEntry or Scenario.

Tests

  • spec/services/example_registry_spec.rb — loading, lookup, tag filtering, sorting, reload
  • spec/services/example_entry_spec.rb — attribute parsing, source file path, default position

See Also

  • Examples Runner — defines how scenarios within examples are executed interactively.
  • Rich Example Content — Markdown-driven detail page layout replacing the fixed description/source/scenarios structure.
  • Home Page — displays a preview of up to six examples from the registry on the landing page.

Change Log

  • 2026-03-05: Initial retrospective spec.
  • 2026-03-09: Prospective update — added boilerplate_file per scenario; removed top-level entry_class/entry_method; updated detail page source display behaviour.
  • 2026-03-23: Prospective update — source_file made optional; examples without it use example.md as sole content driver (case studies); <!-- source --> silently removed when absent.