Template::Pug - Pug templates implementation for Perl
use Template::Pug;
my $tp = Template::Pug->new;
$tp->render(<<'EOF', {list_name => 'List', list => ['foo', 'bar']});
div
p= $list_name
ul#some_id
- for my $item (@$list)
li.some_class= $item
my $tp = Template::Pug->new;
$tp->render_file('template.pug', { user => {name => 'Foo', count => 42} });
# template.pug
# div.
# Hello, #{$user->{name}}!
# You are #{$user->{count}}'th user to signup here!
Template::Pug is a Perl implementation of JavaScript template engine Pug
Tag attributes look similar to HTML, but their values are Perl expressions.
a(href="yandex.ru") Yandex
// <a href="yandex.ru">Yandex</a>
a(href="yandex.ru" class="button") Yandex
// <a href="yandex.ru" class="button">Yandex</a>
Note: since it is impossible(for me) to parse Perl, you can define multiple attributes in one line if expression consists only of single/double quoted string followed by space or comma. Otherwise, every thing until the end of line or end of attribute block is considered single Perl expression.
// Wrong!
- my $authenticated = 1;
div(class=$authenticated ? 'auth' : 'anon' id="bar") Content
// Right
div(id="bar" class=$authenticated ? 'auth' : 'anon') Content
// Right
div(
id=$id
class=$authenticated ? 'auth' : 'anon'
foo=$bar->baz()
) Content
By default, all attribute values are escaped. If you need to use special characters, use !=
instead of =
.
div(escaped="<code>")
// <div escaped="<code>"></div>
div(unescaped!="<code>")
// <div unescaped="<code>"></div>
Boolean attributes are mirrored by Pug. Only literal string undef
is considered false, every thing else is true. When no value is specified true is assumed.
input(foo bar='baz')
// <input bar="baz" foo="foo"/>
input(foo="foo" bar='baz')
// <input bar="baz" foo="foo"/>
input(bar='baz' foo=undef)
// <input bar="baz"/>
The style
attribute can be a hash.
a(style={color => 'red', background => 'green'})
// <a style="background:green;color:red"></a>
The class
attribute can be an array of names.
- my $classes = ['foo', 'bar', 'baz'];
a(class=$classes)
// <a class="foo bar baz"></a>
a.bang(
class=$classes
class=['bing']
)
// <a class="bang foo bar baz bing"></a>
It can also be a hash which maps class names to true or false values. This is useful for applying conditional classes
- my $currentUrl = '/about';
a(href='/' class={active => $currentUrl eq '/'}) Home
// <a href="/">Home</a>
a(href='/about' class={active => $currentUrl eq '/about'}) About
// <a class="active" href="/about">About</a>
Classes may be defined using a .classname
syntax.
div.foo
// <div class="foo"></div>
div
is the default tag so you can omit its tag name.
.foo
// <div class="foo"></div>
IDs may be defined using a #idname
syntax.
div#foo
// <div id="foo"></div>
div
is the default tag so you can omit its tag name.
#foo
// <div id="foo"></div>
Pronounced as “and attributes”, the &attributes
syntax can be used to explode a hach into attributes of an element.
div#foo(data-bar="foo")&attributes({"data-foo" => "bar"})
// <div data-bar="foo" data-foo="bar" id="foo"></div>
- my $attributes = {id => undef, class => 'baz'};
div#foo(data-bar="foo")&attributes($attributes)
// <div class="baz" data-bar="foo"></div>
Attributes applied using &attributes
are not automatically escaped.
Code starts with -
and does not directly add anything to the output. If code element have child than open and closing curly braces added around its content.
// Wrong!
- for (0..2) {
li item
- }
// Right
- for (0..2)
li item
// <li>item</li><li>item</li><li>item</li>
Code block starts with -\n
.
-
my @list = qw/one
two
three/;
- for(@list)
li= $_
// <li>one</li><li>two</li><li>three</li>
Buffered comments //
act like markup tags, producing HTML comments in the rendered page. Like tags, they must appear on their own line.
// some comments
div foo
Will produce:
<!-- some comments -->
<div>foo</div>
Unbuffered comments //-
are only for commenting on the Pug code itself, and do not appear in the rendered HTML.
//- some comments
div foo
Will produce:
<div>foo</div>
Block comments are also an option.
// some
multiline
comment
div foo
Will produce:
<-- some
multiline
comment -->
<div>foo</div>
Moreover, since all lines beginning with <
are treated as plain text, normal HTML-style conditional comments work just fine.
div
<-- HTML comments -->
foo
Will produce:
<div><-- HTML comments -->foo</div>
There are shortcuts for commonly used doctypes:
doctype html
// <!DOCTYPE html>,
doctype xml
// <?xml version="1.0" encoding="utf-8" ?>,
doctype transitional
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,
doctype strict
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">,
doctype frameset
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">,
doctype 1.1
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">,
doctype basic
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">,
doctype mobile
// <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">,
doctype plist
// <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
Or you can use custom doctype.
doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">
If, for whatever reason, it is not possible to use the doctype
keyword, but you would still like to specify the doctype of the template, you can do so via the doctype
option.
$tp->render('img src="foo"', {doctype => 'html'})
// <img src="foo">
$tp->render('img src="foo"', {doctype => 'xml'})
// <img src="foo"></img>
Expression starts with =
. It evaluates the Perl code and outputs the result. For security, expression output is HTML escaped.
p= 'This is <escaped> expression'
// <p>This is <escaped> expression</p>
Unescaped expression starts with !=
.
p!= 'This is <unescaped> expression'
// <p>This is <unescaped> expression</p>
Includes allow you to insert the contents of one Template::Pug file into another.
// main.pug
div
include head.pug
p content
include foot.pug
// head.pug
p head
// foot.pug
p foot
Will produce:
<div>
<p>head</p>
<p>content</p>
<p>foot</p>
</div>
If the path is absolute (e.g., include /root.pug), it is resolved by prepending basedir
option. Otherwise, paths are resolved relative to the current file being compiled. If no file extension is given, .pug
is automatically appended to the file name.
Including files that are not a Template::Pug templates simply includes their raw text.
// main.pug
head
style
include style.css
script
include script.js
body
div foo
// style.css
div {
color: red;
}
// script.js
console.log('Hi!');
Will produce:
<head>
<style>
div {
color: red;
}
</style>
<script>
console.log('Hi!');
</script>
</head>
<body>
<div>foo</div>
</body>
Template::Pug supports template inheritance. Template inheritance works via the block
and extends
keywords. If no file extension is given, .pug
is automatically appended to the file name. In a template, a block
is simply a “block” of Template::Pug code that a child template may replace. This process is recursive. Blocks can have default content.
// layout.pug
html
head
title My Title
block scripts
script(src='/jquery.js')
body
block content
block foot
#footer
p some footer content
//- page-a.pug
extends layout.pug
block scripts
script(src='/jquery.js')
script(src='/pets.js')
block content
h1= $title
- my $pets = ['cat', 'dog'];
- for my $pet (@$pets)
include pet.pug
//- pet.pug
p= $pet
Template::Pug allows you to replace
(default), prepend
, or append
blocks. For example you can have default scripts in head
block that you want to use on every page and just append
scripts you need for current page.
// layout.pug
html
head
block head
script(src='/jquery.js')
script(src='/default.js')
body
block content
// page.pug
extends layout.pug
block append head
script(src='/actions.js')
When using block append
or block prepend
, the word “block” is optional.
In text block any Perl expression put between #{
and }
will be evaluated and result will be escaped and put in its place.
- my $foo = 'simple string';
- my $bar = '<p>string inside tag</p>';
p some text #{10+10} some text #{$foo} some text #{$bar}
// <p>some text 20 some text simple string some text <p>string inside tag</p></p>
If you need to put literal #{
in text just put slash in front of it to escape.
p some text \#{foo} some text
// <p>some text #{foo} some text</p>
Use !{ }
if you want an unescaped result.
- my $foo = '<p>string inside tag</p>';
div some text !{$foo}
// <div>some text<p>string inside tag</p></div>
Text between #[
and ]
will be evaluated as Template::Pug code and result will be put in its place.
p text #[em foo] text #[em(foo='bar') baz] text
// <p>text <em>foo</em> text <em foo="bar">baz</em> text</p>
There is no Mixins yet.
By default, text at the start of a line represents an HTML tag. Indented tags are nested, creating the tree structure of HTML.
body
div
h1 title
p text
// <body>
// <div>
// <h1>title</h1>
// <p>text</p>
// </div>
// </body>
To save space, Template::Pug provides an inline syntax for nested tags.
a: img
// <a><img /></a>
Tags such as img, meta, and link are automatically self-closing (unless you use the XML doctype). You can also explicitly self close a tag by appending the / character.
foo/
foo(bar='baz')/
// <foo/>
// <foo bar="baz" />
The easiest way to add plain text is inline. The first term on the line is the tag itself. Everything after the tag and one space will be the text contents of that tag.
p some plain <em>text</em>
// <p>some plain <em>text</em></p>
Lines starting with <
or |
are treated as plain text.
<body>
p
| some
| text
</body>
// <body>
// <p>some text</p>
// </body>
To add block of text to a tag use .
followed by a new line.
script.
if(true) {
console.log('true');
} else {
console.log('false');
}
Template::Pug implements the following attributes.
my $code = $tp->append;
$tp = $tp->append('warn "Processed template"');
Append Perl code to compiled template.
my $basedir = $tp->basedir;
$tp = $tp->basedir('templates');
Bsaedir used to resolve absolute path in template includes and extends.
my $cache = $tp->cache;
$tp = $tp->cache(1);
Cache is a flag, if set to true will cache and reuse compiled templates. Requires filename
as a cache key. Defaults to false.
my $doctype = $tp->doctype;
$tp = $tp->doctype('html');
Doctype used to specify doctype
if unable to do it in template.
my $encoding = $tp->encoding;
$tp = $tp->encoding('cp1251');
Encoding used for template files, defaults to UTF-8
.
my $namespace = $tp->namespace;
$tp = $tp->namespace('main');
Namespace used to compile templates, defaults to Template::Pug::SandBox
. Note that namespaces should only be shared very carefully between templates, since functions and global variables will not be cleared automatically.
my $code = $tp->prepend;
$tp = $tp->prepend('my $self = shift;');
Prepend Perl code to compiled template.
my $pretty = $tp->pretty;
$tp = $tp->pretty(1);
Pretty is a flag, if set to true adds whitespace to the resulting HTML to make it easier for a human to read using ' '
as indentation. Used for debugging only. Defaults to false.
my $output = $tp->render('div Hello world!');
my $output = $tp->render('p= $foo', {foo => 'bar'});
my $output = $tp->render('p= 1 + 1', {namespace => 'main'});
Render inline template and return the result.
my $output = $tp->render_file('templates/foo.pug');
my $output = $tp->render_file('templates/foo.pug', {foo => 'bar'});
my $output = $tp->render_file('templates/foo.pug', {cache => 1});
Same as "render", but renders a template file.