Руководство по рендеренгу в Perl-фреймворке Mojolicious
Translations of this material:
- into Russian: Руководство по рендерингу в Perl-фреймворке Mojolicious. Translation complete.
-
Submitted for translation by xoma 08.07.2010
Published 1 year, 6 months ago.
Text
# Copyright (C) 2008-2010, Sebastian Riedel.
=encoding utf8
=head1 NAME
Mojolicious::Guides::Rendering - Rendering
=head1 OVERVIEW
Generating content with the L<Mojolicious> renderer.
=head1 CONCEPTS
Essentials every L<Mojolicious> developer should know.
=head2 Renderer
The renderer is a tiny black box turning stash data into actual responses
utilizing multiple template systems and data encoding modules.
{text => 'Hello!'} -> 200 OK, text/plain, 'Hello!'
{json => {x => 3}} -> 200 OK, application/json, '{"x":3}'
{text => 'Oops!', status => '410'} -> 410 Gone, text/plain, 'Oops!'
Templates can be automatically detected if enough information is provided by
the developer or routes.
Template names are expected to follow the C<name.format.handler> scheme, with
C<name> defaulting to C<controller/action> or the route name, C<format>
defaulting to C<html> and C<handler> to C<ep>.
{controller => 'users', action => 'list'} -> 'users/list.html.ep'
{route => 'foo', format => 'txt'} -> 'foo.txt.ep'
{route => 'foo', handler => 'epl'} -> 'foo.html.epl'
All templates should be in the C<templates> directory of the application
or the C<DATA> section of the class C<main>.
__DATA__
@@ time.html.ep
<!doctype html><html>
<head><title>Time</title></head>
<body><%= localtime time %></body>
</html>
@@ hello.txt.ep
...
The renderer can be easily extended to support additional template systems
with plugins, but more about that later.
=head2 Embedded Perl
L<Mojolicious> includes a minimalistic but very powerful template system out
of the box called Embedded Perl or C<ep> for short.
It allows the embedding of Perl code right into actual content using a small
set of special tags and line start characters.
<% Inline Perl %>
<%= Perl expression, replaced with XML escaped result %>
<%== Perl expression, replaced with raw result %>
<%# Comment, useful for debugging %>
% Perl line
%= Perl expression line, replaced with XML escaped result
%== Perl expression line, replaced with raw result
%# Comment line, useful for debugging
The simplest form is used to insert raw Perl code.
Tags and lines work pretty much the same, but depending on context one will
usually look a bit better.
<% my $i = 10; %>
Text before.
<% for (1 .. $i) { %>
Insert this text 10 times!
<% } %>
Text after.
% my $i = 10;
Text before.
% for (1 .. $i) {
Insert this text 10 times!
% }
Text after.
You can also insert results from actual Perl code using expressions, by
default the characters C<E<lt>>, C<E<gt>>, C<&>, C<'> and C<"> will be
escaped to prevent XSS attacks against your application.
Semicolons get automatically appended to all expressions.
<%= 'lalala' %>
<%== '<p>test</p>' %>
Only L<Mojo::ByteStream> objects are excluded from automatic escaping.
<%= Mojo::ByteStream->new('<p>test</p>') %>
You can also add an additional equal sign to the end of a tag to have it
automatically remove all surrounding whitespaces, this allows free indenting
without ruining the result.
<% for (1 .. 3) { %>
<%= $foo =%>
<% } %>
Comment tags and lines are very useful to deactivate code for debugging
purposes.
% my $foo = 'lalala';
<%# if ($foo) { %>
<%= $foo =%>
<%# } %>
Stash values that don't have invalid characters in their name get
automatically initialized as normal variables in the template and the
controller instance as C<$self>.
$r->route('/foo/:name')
->to(controller => 'foo', action => 'bar', name => 'tester');
Hello <%= $name %>.
There are also many built in helper functions such as C<url_for>, which
allows you to generate the URL of a specific route just from its name.
$r->route('/foo/:name')->to('foo#bar')->name('some_route');
<%= url_for 'some_route' %>
=head1 BASICS
Most commonly used features every L<Mojolicious> developer should know about.
=head2 Automatic Rendering
The renderer can be manually started by calling the C<render> controller
method, but thats usually not neccessary, because it will get automatically
called if nothing has been rendered after the routes dispatcher finished its
work.
This also means you can have routes pointing only to templates without actual
actions.
$self->render;
There is one big difference though, by calling C<render> manually you can
make sure that templates use the current controller instance and not the
default controller specified in the C<controller_class> attribute of the
application class.
=head2 Rendering Templates (C<template>)
The renderer will always try to detect the right template but you can also
use the C<template> stash value to render a specific one.
$self->render(template => 'foo');
Choosing a specific C<format> and C<handler> is just as easy.
$self->render(template => 'foo', format => 'txt', handler => 'epl');
Because rendering a specific template is the most common task it also has a
shortcut.
$self->render('foo');
All values passed to the C<render> call are only temporarily assigned to the
stash and get reset again once rendering is finished.
=head2 Rendering Text (C<text>)
Plain text can be rendered with the C<text> stash value, characters get
automatically encoded to bytes.
$self->render(text => 'Hello Wörld!');
=head2 Rendering Data (C<data>)
Raw bytes can be rendered with the C<data> stash value, no encoding will be
performed.
$self->render(data => $octets);
=head2 Rendering JSON (C<json>)
The C<json> stash value allows you to pass Perl structures to the renderer
which get directly encoded to JSON.
$self->render(json => {foo => [1, 'test', 3]});
=head2 Partial Rendering (C<partial>)
Sometimes you might want to access the rendered result, for example to
generate emails, this can be done using the C<partial> stash value.
my $html = $self->render('mail', partial => 1);
=head2 Status Code (C<status>)
Response status codes can be changed with the C<status> stash value.
$self->render(text => 'Oops!', status => 500);
=head2 Content Type (C<format>)
The C<Content-Type> header of the response is actually based on the MIME type
mapping of the C<format> stash value.
$self->render(text => 'Hello!', format => 'txt');
These mappings can be easily extended or changed.
# Application
package MyApp;
use base 'Mojolicious';
sub startup {
my $self = shift;
# Add new MIME type
$self->types->type(txt => 'text/plain; charset=utf-8');
}
1;
=head2 Helpers
Helpers are little functions that are stored in the renderer, not all of them
are strictly template specific, thats why you can also use the C<helper>
controller method to call them.
<%= dumper [1, 2, 3] %>
my $serialized = $self->helper(dumper => [1, 2, 3]);
The C<dumper> helper will use L<Data::Dumper> to serialize whatever data
structure you pass it, this can be very useful for debugging.
We differentiate between C<default helpers> which are more general purpose
like C<dumper> and C<tag helpers>, which are template specific and mostly
used to generate C<HTML> tags.
<%= script '/script.js' %>
<%= script {%>
var a = 'b';
<%}%>
The plugins L<Mojolicious::Plugin::DefaultHelpers> and
L<Mojolicious::Plugin::TagHelpers> contain all of them.
=head2 Layouts
Most of the time when using C<ep> templates you will want to wrap your
generated content in a HTML skeleton, thanks to layouts thats absolutely
trivial.
@@ foo/bar.html.ep
% layout 'mylayout';
Hello World!
@@ layouts/mylayout.html.ep
<!doctype html><html>
<head><title>MyApp!</title></head>
<body><%= content %></body>
</html>
You just select the right layout template with the C<layout> helper and place
the result of the current template with the C<content> helper.
You can also pass along normal stash values to the C<layout> helper.
@@ foo/bar.html.ep
% layout 'mylayout', title => 'Hi there!';
Hello World!
@@ layouts/mylayout.html.ep
<!doctype html><html>
<head><title><%= $title %></title></head>
<body><%= content %></body>
</html>
=head2 Including Partial Templates
Like most helpers the C<include> helper is just a shortcut to make your life
a little easier.
@@ foo/bar.html.ep
<!doctype html><html>
<%= include 'header' %>
<body>Bar!</body>
</html>
@@ header.html.ep
<head><title>Howdy!</title></head>
Instead of C<include> you could also just call C<render> with the C<partial>
argument.
@@ foo/bar.html.ep
<!doctype html><html>
<%= $self->render('header', partial => 1) %>
<body>Bar!</body>
</html>
@@ header.html.ep
<head><title>Howdy!</title></head>
Of course you can also pass stash values.
@@ foo/bar.html.ep
<!doctype html><html>
<%= include 'header', title => 'Hello!' %>
<body>Bar!</body>
</html>
@@ header.html.ep
<head><title><%= $title %></title></head>
=head2 Reusable Template Blocks
