NAME

Punk::Views - the pluggable view engine registry (XS)

DESCRIPTION

Each views $name => \%opts call in the DSL registers one engine. $name resolves to Punk::View::$name; '+Full::Class' uses the class as written. The engine contract is two methods and nothing more - adding view backends never touches the dispatch path:

my $engine = Engine->new(\%opts);
my $bytes  = $engine->render($template_name, \%data);
my $bytes  = $engine->render($template_name, \%data, \%opts);   # see below

The first registered engine is the default; $c->render($tpl, \%data, engine => 'Other') selects per render, type => '...' overrides the content type, status => ... the status, and layout => ... the wrapper. Everything resolves and croaks at to_app, never per request. An override not in that list croaks at the render, naming the four that are: an option that is silently skipped is one that looks like it worked.

layout

$c->render('panel/logs', \%data, layout => undef);     # no wrapper
$c->render('mail/reset', \%data, layout => 'mail');    # another one

A template name (resolved like any other, with or without its extension) renders inside that wrapper instead of the configured one; undef renders with none. The option reaches the engine as a third argument, { wrapper => $name | undef }, and only when it was given - an engine written to the two-argument call sees nothing new until a caller asks for a layout, and then ignores it. Punk::View::Stencil honours it; an engine of your own that wants to has the hashref. Everything else about the render is unchanged: the per-request values a plugin binds (csp_nonce, locale) are there, the application's filters run, the pending status and headers fold in.

$c->fragment ("fragment" in Punk::Context) is this with undef and a Cache-Control of private, no-store, for the partial that is one user's data.

Implemented entirely in C (include/punk/punk_views.h): the object is a blessed IV-ref to the engine registry, and render - the hot path - looks the engine up, calls its render, and assembles the PSGI triplet in C, so a rendered page crosses the Perl boundary only for the engine's own render (itself XS in Template::Stencil).

METHODS

new(\@pairs)

Compile the registry from [ [ $name, \%opts ], ... ]. Resolves, loads and instantiates each engine; the first is the default. Duplicate names, a class that will not load, or one missing new/render croak.

engine($name?)

The named (or default) engine instance; unknown names croak listing what is registered.

default

The default engine's name.

render($c, $template, \%data, %overrides)

A finished PSGI triplet around the engine's bytes, folding in any status and headers pending on the context $c (which may be undef). Overrides: status, type, engine, layout; any other croaks, as does an override name with no value after it.

AUTHOR

LNATION <email@lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION <email@lnation.org>.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)