NAME

Database::BI::Tutorial - the chapters of the in-application tutorial

SYNOPSIS

use Database::BI::Tutorial;

for my $part (@{ Database::BI::Tutorial->parts }) {
    print $part->{name}, ": ", scalar @{ $part->{chapters} }, " chapters\n";
}

my $chapter = Database::BI::Tutorial->chapter_for_action('bar_view');
print $chapter->{title}, "\n" if $chapter;

DESCRIPTION

The tutorial that the application shows at GET /tutorial is built from the data in this module. A chapter is one feature: a title, a short lead, numbered steps, and the routes that it covers. The template renders the chapters in order, so adding a feature means adding a hash here, not editing HTML.

A chapter may also have a walkthrough: a worked example with a title, an intro, a list of steps that each say what to do and what to see, and a result. The template shows it as one box, and the contents marks the chapter so a reader can find it.

t/tutorial.t checks that every GET page in Database::BI is either covered by a chapter or listed in exempt_routes() with a reason. Keep the sentences short: the same test fails a lead, step, tip or walk-through sentence longer than 25 words.

chapter_for_action() maps a controller action to the chapter that helps with that page. The application calls it from a before_render hook and the shared layout shows the result as a Help: ... link beside the main Tutorial link. A new page action belongs in %ACTION_CHAPTERS; the test fails until it is there.

FUNCTIONS

Each is called as a class method or a plain function; none takes arguments except chapter_for_action. The returned structures are the module's own data: read them, do not change them.

intro

API SPECIFICATION

OUTPUT

[ 'string', ... ]   # the introduction's sentences

chapters

API SPECIFICATION

OUTPUT

[ {
    id     => 'string',     # anchor, unique
    part   => 'string',     # the part the chapter belongs to
    title  => 'string',
    lead   => 'string',
    steps  => 'arrayref',   # sentences
    tip    => 'string',     # optional
    try    => 'hashref',    # optional; { href, label }
    routes => 'arrayref',   # the GET routes the chapter covers
    walkthrough => 'hashref', # optional; { title, intro, steps => [ { do, see } ], result }
}, ... ]

In the order the page shows them.

faq

API SPECIFICATION

OUTPUT

[ { question => 'string', answer => 'string' }, ... ]

glossary

API SPECIFICATION

OUTPUT

[ { term => 'string', meaning => 'string' }, ... ]

parts

API SPECIFICATION

OUTPUT

[ { name => 'string', id => 'string', chapters => 'arrayref' }, ... ]

The chapters grouped by part, in order. id is the part name in lower case with each run of other characters replaced by -. A new list is built on each call.

covered_routes

API SPECIFICATION

OUTPUT

{ '/route' => 'chapter-id', ... }

A route named by two chapters maps to the later one.

exempt_routes

API SPECIFICATION

OUTPUT

{ '/route' => 'reason', ... }   # a copy: GET pages with no chapter, and why

chapter_for_action

API SPECIFICATION

INPUT

$action   # a controller action name, e.g. 'bar_view'

OUTPUT

A chapter hashref (as C<chapters> returns), or an empty list

An undefined or unknown action returns an empty list. It must be called as a class method: the action is the second argument.

AUTHOR

Nigel Horne <njh@nigelhorne.com>

LICENCE AND COPYRIGHT

Copyright 2026 Nigel Horne.

Usage is subject to the GPL2 licence terms.