NAME

YATT::Lite::PageConsts - per-page compile-time constants for templates (pagevars)

SYNOPSIS

In lib/MyApp/PageVars.pm (the pagevars module):

package MyApp::PageVars;
use strict;
use YATT::Lite::PageConsts -as_base, qw(as_html);

my @common = (site_title => "Survey 2026");

MY->define_page(index => {
  title => "Welcome", @common,
});

MY->define_page(q01 => {
  title   => "Question 1",
  choices => my $q01_choices = [qw(yes no)],
  note    => as_html("Choose <b>one</b>."),
  @common,
});

# Constants can refer to each other across pages.
MY->define_page('q01/confirm' => {
  title   => "Confirm Q1",
  choices => $q01_choices,
  @common,
});

MY->cli_run(\@ARGV) unless caller; # optional, see L</COMMAND LINE>
1;

In app.psgi:

use FindBin;
use lib "$FindBin::Bin/lib";
use YATT::Lite::WebMVC0::SiteApp -as_base;

my $site = MY->load_factory_for_psgi(
  $0,
  doc_root => "$FindBin::Bin/public",
  pagevars => 'MyApp::PageVars',
);

In public/q01.yatt:

<h2>&yatt:title;</h2>
<p>&yatt:note;</p>
<yatt:foreach my=c list=choices>&yatt:c; </yatt:foreach>

From ordinary Perl code:

use MyApp::PageVars 'q01';  # imports $title, $choices, $note ...

DESCRIPTION

pagevars is a mechanism to inject per-page constants into yatt templates from outside. The constants of each page are fixed at compile time of the template, and they appear as top-level variables (&yatt:title;), so they are checked statically like widget arguments: a misspelled name is a compile error.

Global constants (shared by all pages) are out of scope of this module; use ordinary Entities for them.

The constants are defined by a Perl module (not by JSON or similar), so that constants can share values and refer to each other across pages, as $q01_choices in the "SYNOPSIS".

Page names

A page name is the path of the template relative to doc_root, without its extension: public/index.yatt is index, public/q01/confirm.yatt is q01/confirm.

Templates outside of doc_root (e.g. ytmpl/*.ytmpl used through app_base) are not pages, so pagevars are not applied to them. Pages which have no entry in the pagevars module simply get no constants.

When per_role_docroot is used, templates under role directories are currently not treated as pages.

Types

The type of each template variable is decided by the value:

plain string or number        text   (escaped on output)
ARRAY ref                     list   (usable in <yatt:foreach list=...>)
as_html("...")                html   (output without escaping)
CODE ref                      expr   (see below)
other refs (HASH ref, object) scalar (e.g. &yatt:opt{key};)

A CODE value is an expr type variable, i.e. a function which computes a value. &yatt:fn(...); calls it with the given arguments (without $CON). Its return value is printed with escaping, and can be used as a value in expressions like <yatt:if "&yatt:fn(...);">.

# pagevars module
$PAGES{index} = +{
  fmt => sub { my ($x) = @_; sprintf "%.2f", $x },
};

<!-- index.yatt -->
<p>&yatt:fmt(3.14159);</p>     <!-- <p>3.14</p> -->

(Compatibility) Before GH-294, a CODE value was a code type variable and its return value was not printed.

Scoping

Page constants form the outermost scope of every widget in the page. Arguments, <yatt:my> variables and loop variables with the same name shadow them silently.

Values are shared

ARRAY/HASH values are exported by reference, not copied. Shared values (like @common above) are shared by all pages and all requests, so do not modify them at runtime.

Reloading

The pagevars module is loaded only once per process. After editing it, restart the application server.

CONFIGS

pagevars

Package name of the pagevars module. It is loaded with require when a template is compiled, so it must be found in @INC (use an absolute path, as "$FindBin::Bin/lib", since rendering may change the current directory). Can be given to load_factory_for_psgi/new of YATT::Lite::WebMVC0::SiteApp, or written in app.yml/app.xhf.

CLASS METHODS

These are called on the pagevars module (MY in the "SYNOPSIS", which is a subclass of YATT::Lite::PageConsts via -as_base), or on YATT::Lite::PageConsts itself.

define_page($page_name, {NAME => VALUE, ...})

Registers the constants of a page into the calling package (the pagevars module). On the first call, the package gets instance, import, and all methods below. It also remembers where this call is written, for locate_page and locate_const (used by LanguageServer).

Defining the same page twice is an error, which reports both locations.

define_pages_from_hash(\%PAGES)

Registers all pages in %PAGES (page name => HASH of constants) at once. This is mainly for migration from the old YATT::Util::VarExporter. Since the location of each page is unknown, locate_page guesses it from the source with page_key_regexp. Prefer define_page.

as_html($text)

Marks $text as HTML, which is printed without escaping. Exportable: use YATT::Lite::PageConsts qw(as_html).

const_type($value)

Returns the yatt variable type for $value: text, list, html, code or scalar. See "Types".

METHODS

These can be called both as class methods of the pagevars module (which delegate to its instance) and as instance methods.

find_consts($page, [$name])

Returns the HASH of constants of $page, or the value of constant $name of it. Returns nothing for unknown pages.

locate_const($page, $name)

Returns ($file, $line) (1-based line) where the constant is defined in the pagevars module, or an empty list for unknown pages and names. It looks for const_key_regexp in the block of the page first (see page_block_range), then anywhere in the file (for common values like @common), then falls back to locate_page. Used by YATT::Lite::LanguageServer for definition/hover.

locate_page($page)

Returns ($file, $line) where the page is defined: the line of define_page, or for pages from define_pages_from_hash, the first line which matches page_key_regexp.

page_block_range($page, \@lines)

Returns the block of the page in @lines (the source of the pagevars module) as 0-based ($start, $end): from the define_page call of the page to just before the next one. For pages from define_pages_from_hash, the block ends just before a line which matches page_key_regexp of another page.

inject_into($destpkg, $page, %opts)

Installs the constants of $page into package $destpkg as package variables ($name; CODE values also as &name). Dies for unknown pages unless missing_ok => 1 is given. Generated code of templates calls this through import with missing_ok => 1.

import($page) (of the pagevars module)

use MyApp::PageVars 'q01';

Calls inject_into for the caller package.

HOOKS

page_name

When $page is omitted (use MyApp::PageVars;), inject_into calls page_name method of the pagevars module if it exists, and dies otherwise. Define it in the pagevars module to choose the default page (this requires define_page to be called on the pagevars module, as MY->define_page(...)).

const_key_regexp($name), page_key_regexp($page), page_call_regexp

Regexps used to find locations in the source of the pagevars module: the key of a constant (default: NAME =>), the key of a page in a hash of pages (default: $PAGES{PAGE} = or PAGE =>, only for define_pages_from_hash), and the line which starts a define_page call (caller may report a line inside a block like map {...} in its arguments, so the location is moved back to the line matching this).

Override them in the pagevars module to support local notations. For example, if constants are written as comma separated pairs:

sub const_key_regexp {
  my ($self, $name) = @_;
  qr/(['"])\Q$name\E\1\s*,/;
}

MY->define_page(q01 => {
  'title', "Question 1",
});

COMMAND LINE

The pagevars module is a MOP4Import::Base::CLI_JSON class. With MY->cli_run(\@ARGV) unless caller; at its end, it can be run as a command to inspect the constants:

% perl -Ilib lib/MyApp/PageVars.pm find_consts q01
% perl -Ilib lib/MyApp/PageVars.pm locate_page q01
% perl -Ilib lib/MyApp/PageVars.pm locate_const q01 title

SEE ALSO

YATT::Lite::WebMVC0::SiteApp, YATT::Lite::LanguageServer

AUTHOR

KOBAYASI, Hiroaki <hkoba@cpan.org>