| App::FuguWeb(3p) | Perl Library Manual | App::FuguWeb(3p) |
NAME
App::FuguWeb - a static documentation site for a Perl project
SYNOPSIS
fuguweb build --out web/build
fuguweb check --out web/build
use App::FuguWeb;
my $safe = App::FuguWeb::escape_html($title);
my $file = App::FuguWeb::CONFIG_FILE; # .fuguwebrc
DESCRIPTION
"fuguweb" renders one static site from the documentation that a Perl project already keeps: mdoc(7) manuals, POD sidecars, and Markdown. There is no templating language and no JavaScript. The tool runs "mandoc", "lowdown", and "pod2man", and wraps each result in one shared chrome.
A project needs no build recipe. It writes one .fuguwebrc at its root, keeps its body fragments and its assets in one source directory, and runs "fuguweb build". See fuguweb(1) for the subcommands and the exit codes.
This file holds what more than one module in the namespace needs: two constants and four functions, documented below. The rest of the work is split by concern:
- App::FuguWeb::Config
- The site description: the settings, the navigation, the pages, and the manual groups.
- App::FuguWeb::Page
- The chrome around one body fragment.
- App::FuguWeb::Render
- The three external renderers.
- App::FuguWeb::Manual
- One manual source: its path, name, section, page, and description.
- App::FuguWeb::Index
- The body of the manual index.
- App::FuguWeb::Site
- The whole build.
- App::FuguWeb::Check
- The checks over a built site.
- App::FuguWeb::CLI
- Subcommand dispatch over Fugu::CLI.
THE CONFIGURATION FILE
.fuguwebrc sits at the project root and uses the Fugu::Config grammar: a setting on a line of its own, and a block that opens with a brace at the end of its header line. A "#" starts a comment, and the grammar has no escape for it, so a value may not hold one.
site = OpenHAP
out_dir = web/build
source_dir = web
entry = index.html
nav "fugu.html" {
label = Fugu
}
page "install.html" {
title = Install
markdown = INSTALL.md
}
manuals fugu {
heading = Fugu
dir = man/fugu
namespace = "Fugu::"
}
modules modules {
heading = OpenHAP modules
dir = lib/App/OpenHAP
}
page de "install.html" {
title = Installation
markdown = INSTALL.de.md
}
A "page" block names exactly one source: "body" for a fragment in the source directory, "markdown" for a Markdown file, or "index = yes" for the generated manual index. An index page can take a "body" that opens it. "unlinked = yes" marks a page that no other page links to, such as 404.html.
The block name of a group is its anchor on the index page, and "heading" holds the text. A block with a language code in front of its name is a translation into that language. Each language of the site takes one tree of the output, and "Translations" in App::FuguWeb::Config states the rules.
Three rules keep a list out of the file. A "manuals" block reads its directory. A "modules" block finds every .pod file below its directory, and the sidecar that names the directory itself. Every file in the source directory that the build does not render is an asset, and the build copies it; "ASSETS" in App::FuguWeb::Site says exactly which those are.
A "keys" block and its "key" blocks describe the published key directory of an organization. App::FuguWeb::Keys documents them.
App::FuguWeb::Config documents every setting and every default.
FUNCTIONS
escape_html
my $safe = App::FuguWeb::escape_html($text);
Escape "&", "<" and ">", in that order. The function takes bytes and returns bytes: no file in the namespace carries "use utf8", so a multi-byte character passes through untouched.
escape_attr
my $safe = App::FuguWeb::escape_attr($text);
The same, plus the double quote. Use it for a value on its way into a double-quoted attribute: a value that holds a quote ends the attribute early, and everything after it becomes markup. "escape_html" alone does not guard an attribute.
list_dir
my $names = App::FuguWeb::list_dir($dir) or die "cannot read: $!";
The names in one directory, sorted, without "." and "..". The function returns an array reference, or "undef" with the reason in $!, so a caller can tell an empty directory from one it cannot read.
The sort compares bytes and never reads the locale of the builder: a site must not depend on the machine that built it.
list_tree
my $paths = App::FuguWeb::list_tree($dir) or die "cannot read: $!";
Every leaf below the directory, as paths relative to it: each file, each symlink, and each directory that holds nothing. The function returns an array reference, or "undef" with the reason in $!.
The function recurses into a plain directory, and never through a symlink. A symlinked directory is one entry: the build owns neither the target of the link nor what sits under it.
An empty directory is a leaf, so a caller sees it. A walk that answered with files alone would hide a stray directory from the checks, and the clean refuses one.
Each language tree and each key directory sits below the top level of a site. The output therefore needs a walk of the tree wherever a walk of one level would serve one directory.
path_below
App::FuguWeb::path_below($path, $root)
Report whether $path is $root or lies below it. A trailing slash on either does not change the answer. Both paths must be of the same kind: both absolute, or both relative to the same directory.
CONSTANTS
CONFIG_FILE
The name of the configuration file, .fuguwebrc. The name and the discovery match .fuguvmrc.
STAGING_DIR
The staging directory for the mdoc sources, inside the output directory. The build makes it, uses it, and removes it again.
The name lives here because two modules need it. App::FuguWeb::Site owns the directory, and App::FuguWeb::Config must refuse a key directory of the same name: the build would remove the published keys with the staging.
STYLESHEET
The name of the stylesheet in the output directory, style.css. The build writes it at the top level, outside every language tree. Each page but the forward index.html links it with a relative path, and the forward loads nothing.
DEFAULT_LANGUAGE
The code of the default language, "en". Every page of the description renders in the tree of this language. The key page and the two pages of the top level are pages of it.
LANGUAGE_CODE
The shape of a language code, as a compiled pattern: two lowercase ASCII letters. A directory at the top level of the output whose name takes this shape holds a language tree.
FORWARD_PAGE, NOT_FOUND_PAGE
The two pages of the top level, index.html and 404.html. The first forwards to the entry page of the default tree. The second is a copy of the 404 page of the default tree, for the host.
SEE ALSO
fuguweb(1), Fugu::Config, mandoc(1), lowdown(1), pod2man
AUTHOR
Dick Olsson <hi@senzilla.io>
| 2026-10-21 | OpenBSD |