mojo lite学习笔记之Perl风格的模板
在对mojo有初步认识之后(mojo lite学习笔记之自身用法),接下来介绍它的另一个非常赞的功能块:Perl风格的模板。Mojo::Template - Perl-ish templates!
Mojo::Template is a minimalistic and very Perl-ish template engine, designed specifically for all those small tasks that come up during big projects. Like preprocessing a configuration file, generating text from heredocs and stuff like that.
可参见 Mojolicious::Guides::Rendering 章节可获得更多关于 Mojolicious renderer的参考,下面是模板的一些内置语法。
<% Perl 代码 %>
<%= Perl 表达式, 结果表达式的值 %>
<%== Perl 表达式, 结果是什么就显示什么 %>
<%# 注释, 用于 debug %>
<%% 替换为 "<%", 用于生成模板 %>
% Perl 代码行,和这个一样 "<% line =%>"
%= Perl 表达式,这个一样 "<%= line %>"
%== Perl 达式,这个一样 "<%== line %>"
%# 注释,这个一样 "<%# line =%>"
%% 换为 "%", 用于生成模板
Stash and templates
这个 "stash" in Mojolicious::Controller 是用来传一些数据给模板技术使用,在这我们使用的是 DATA 这个部分的模板。像模板中传入参数有两种方式:stash方法与render('模板名',参数列表).
# /bar
get '/bar' => sub {
my $self = shift;
$self->stash(one => 23);
$self->render('baz', two => 24);
};
app->start;
__DATA__
@@ baz.html.ep
The magic numbers are <%= $one %> and <%= $two %>.
更多有关模板的信息可以看看 "Embedded Perl" in Mojolicious::Guides::Rendering.
Layouts
模板是可以分层的,你只需要选择 helper 中的 "layout" in Mojolicious::Plugin::DefaultHelpers。给当前结果放到模板中通过 "content" in Mojolicious::Plugin::DefaultHelpers.
# /with_layout
get '/with_layout' => sub {
my $self = shift;
$self->render('with_layout');
};
app->start;
__DATA__
@@ with_layout.html.ep
% title 'Green';
% layout 'green';
Hello World!
@@ layouts/green.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>
个人觉得这个功能用处有限,没有深入了解学习。是用来规划布局的吗?
Blocks
模板可以使用标准的 Perl 的功能,只需要使用 begin 和 end 的关键字分隔.
# /with_block
get '/myblock'=>sub{
my $c = shift;
$c->stash(title => 'Mojo Temp Var');
}=> 'block';
app->start;
__DATA__
@@ block.html.ep
%= link_to Home => 'index'
% use Time::Piece;
% my $link = begin
% my ($url, $name) = @_;
Use <%= link_to $name => $url %>
% end
% my $dt = localtime;
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
<p><%= $dt->datetime %></p>
<%= $link->('http://www.freeoa.net','FreeOA') %>
%= $link->('http://mojolicio.us', 'Mojolicious')
</body>
</html>
Captured content
在 helper 中可以使用 "content_for" in Mojolicious::Plugin::DefaultHelpers 来抓到包在一个块中的内容,多次调用会将内容追加。
# /captured
get '/captured' => sub {
my $self = shift;
$self->render('captured');
};
app->start;
__DATA__
@@ captured.html.ep
% layout 'blue', title => 'Green';
% content_for header => begin
<meta http-equiv="Pragma" content="no-cache">
% end
Hello World!
% content_for header => begin
<meta http-equiv="Expires" content="-1">
<meta http-equiv="Content-Language" content="zh-CN">
% end
@@ layouts/blue.html.ep
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
%= content_for 'header'
</head>
<body><%= content %></body>
</html>
模板的表单指定方法(get,post):
<%= form_for '/cities' => (method => 'post') => begin %>
Name: <%= text_field 'name' %>
Info: <%= text_field 'info' %>
<%= submit_button 'Submit' %>
<% end %>
"form_for" creates a HTML form tag, submitted data is send to 'http://localhost:3000/cities', and the information is send via the "POST" method.
<% for my $method ( qw[ get post ] ) %>
<% for my $action ( qw[ simple error ] ) %>
%= form_for $action => (method => $method) => begin
%= hidden_field toy_number => 42
%= submit_button "$method /$action"
%= end
post方法的写法
Posting forms depends on which version of Mojolicious you are using. Until recently (v3.85 -- 2013-02-13) there was a post_form method. On reflection however, it was decided there should either be *_form methods for every request type, or we should do something smarter, and thus the form generator was born.
$response_vt = $ua->post($url, form => {'apikey' => $key, 'resource' => $md5}, sub { ... });
It can be added to any request method, making it much more consistent than the old form. Also note that it should be a hashref, not an arrayref as LWP allows. BTW there is also a json generator that works like this too, or you can even add your own!
$ua->post( $url, \%form );
$ua->post( $url, \@form );
which you provide in the first script in the ref to array format "\@form"
my $response = $ua->post( $url, ['apikey' => $key, 'resource' => $md5] );
being as it is a hash this is probably better written in the hash format "\%form"
my $response = $ua->post( $url, {'apikey' => $key, 'resource' => $md5} );
In Mojo::UserAgent the arguments to post are a little more complex, but essentially appear to be a "string" of hash refs to hash keys, with which I am unfamiliar. However you may find using the hash ref format provides the expected arguments correctly.
UserAgent#post
POST
my $tx = $ua->post('freeoa.net');
my $tx = $ua->post('http://freeoa.net' => {DNT => 1} => 'Hi!');
my $tx = $ua->post('http://freeoa.net' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->post('http://freeoa.net' => {DNT => 1} => json => {a => 'b'});
try this ?:
$response_vt = $ua->post( $url => form => {'apikey' => $key, 'resource' => $md5} => sub {... });
参考文档:http://mojolicio.us/perldoc/Mojolicious/Plugin/TagHelpers#form_for
外部模板
外部模板会从你的应用目录中的 templates 目录中来查找.
use Mojolicious::Lite;
# /external
any '/external' => sub {
my $self = shift;
# templates/foo/bar.html.ep
$self->render('foo/bar');
};
app->start;
静态文件
静态文件可以从 DATA 的部分(可以是 Base64 的编码)或 public 的目录查找.
@@ something.js
alert('hello!');
@@ test.txt (base64)
dGVzdCAxMjMKbGFsYWxh
外部静态文件不限于一个单独的文件,如果存在 public 会自动从这个下面查找所需要的文件。
$ mkdir public
$ mv something.js public/something.js
include 其它模板
并为其传入复杂数据结构,下列将展示为include模板,传入hashref。
get '/bar' => sub {
my $self = shift;
$self->stash(one => 23);
my ($sql)=("select id,title,alias,hits from content where catid=1029 limit 10");
$self->render('baz', two => 24,db=>rdb_get_qar($sql));
};
app->start;
baz.html.ep
The magic numbers are <%= $one %> and <%= $two %>.<br />
%= include 'header', title => 'Hello'
<%# 显示第一条记录的title,在页面中将其数据结构打印出来 %>
<%= $db->[0]->{'title'} %>
<%# dumper $db %>
header.html.ep
<head><title><%= $title %></title></head>
% my $i = 12;
<ul>
% for my $j (1 .. $i) {
<li>
%= $j
</li>
% }
</ul>
% for my $d (@$db) {
%= $d->{'title'}
<br />
% }
可见include进来的模板与原始的模板在传入参数上,享有平等的权利。
向模板中传入种复杂变量的处理方法
1)、变通变量
Passing a scalar to the stash
Here is a small code snippet about passing variables to the stash.
use Mojolicious::Lite;
get '/' => sub {
my $self = shift;
$self->stash(
name => 'Peter'
);
} => 'index';
app->start;
__DATA__
@@ index.html.ep
Hello <%= $name %>
2)、数组变量
Passing an array to the stash (by reference)
use Mojolicious::Lite;
get '/' => sub {
my $self = shift;
$self->stash(
names => ['Peter', 'Georg', 'Fabian']
);
} => 'index';
app->start;
__DATA__
@@ index.html.ep
<p>Hello <%= $names->[0] %></p>
<p>List of array members:
<ul>
% foreach my $person (@$names) {
<li><%= $person %></li>
% }
</ul>
</p>
3)、hash ref变量
Passing a hashref to the stash
Now to some more advanced stuff. Passing a hashref is a useful thing as this might be the result of a database query from one of the DBI modules. See selectall_hashref for more information on how to do it.
use Mojolicious::Lite;
get '/' => sub {
my $self = shift;
my $services = {
'rabenfedern.de' => {
'admin' => 'rhaen',
'desc' => 'webserver'
},
'pkgbox.org' => {
'admin' => 'hazel',
'desc' => 'mailserver'
}
};
$self->stash(
services => $services
);
} => 'index';
app->start;
__DATA__
@@ index.html.ep
% layout 'default';
<p>Welcome to hashrefs</p>
<p>
<ul>
% foreach my $domain (keys %{$services}) {
<li><%= $domain %></li>
<ul>
<li>Admin: <%= $services->{$domain}->{admin} %></li>
</ul>
<p>That's a server for: <%= $services->{$domain}->{desc} %></p>
% }
</ul>
</p>
4)、数组 ref 变量
Passing a arrayref to the stash
The following code snippet completes the template code demo session. Voila, working with arrayref inside the stash.
use Mojolicious::Lite;
get '/' => sub {
my $self = shift;
my $ref_pets = [
['isolde', 'cat'],
['oscar', 'dog']
];
$self->stash(
ref_pets => $ref_pets
);
} => 'index';
app->start;
__DATA__
@@ index.html.ep
<p>Welcome to arrayrefs</p>
<p>
<ul>
% for my $loop ( @{$ref_pets} ) {
<li>Name of the pet: <%= $loop->[0] %>, it's a <%= $loop->[1] %></li>
% }
</ul>
</p>