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.