第二十一天 - 一个小小的圣诞节模板烹饪

img

Advent Calendar向您展示了许多使用Mojolicious的好方法,因为您已经安装了Mojo,所以除了Web处理之外,您还可以使用它。今天的配方使用模板渲染引擎进行Web响应之外的其他操作。

首先,处理一些字符串模板。这是使用v5.26中发布波浪形heredoc语法Mojo::Template中取出的一个示例

1
2
3
4
5
6
7
8
9
10
11
use Mojo::Template;

my $mt = Mojo::Template->new;

say $mt->render(<<~'EOF');
% use Time::Piece;
<div>
% my $now = localtime;
Time: <%= $now->hms %>
</div>
EOF

带有前导百分号的行是Perl代码。其中一行加载模块,Time::Piece,另一行创建变量$now。该<%= %>插入值内联。您可以自己找出其他模板语法; 这些都在模块文档中

您可以将其反转,以便值的来源来自模板外部。有时,这比在让表示层中有太多逻辑更可取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use v5.26;
use Mojo::Template;

my $mt = Mojo::Template->new;

use Time::Piece;
my $now = localtime;

say $mt->render(<<~'EOF', $now->hms );
% my $time = shift;
<div>
Time: <%= $time %>
</div>
EOF

如上所示,默认情况下,参数以位置方式传递给模板。然而,通过名称而不是位置来描述变量更为自然。该vars属性打开您将哈希传递给模板的能力; 哈希键成为模板本身的变量名。

1
2
3
4
5
6
7
8
9
10
11
12
13
use v5.26;
use Mojo::Template;

my $mt = Mojo::Template->new->vars(1);

use Time::Piece;
my $now = localtime;

say $mt->render(<<~'EOF', { time => $now->hms } );
<div>
Time: <%= $time %>
</div>
EOF

从文件(或许多文件)中获取该模板同样容易。这是我以前使用Template Toolkit执行此操作的一种方式,这是一个非常精细且功能强大的模块,与以前一样好。但是,我已经在使用了Mojo的很多东西,它已经有了一个模板引擎。我可以减少依赖计数并专注于一种模板语言。

通常,Mojo模板使用扩展名.ep。遍历您在命令行中指定的所有文件,并烹饪具有该扩展名的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use v5.14;
use Mojo::Template;

my $mt = Mojo::Template->new->vars(1);

use Time::Piece;
my $now = localtime;

foreach my $file ( @ARGV ) {
my $new_file = $file =~ s/\.ep\z//r;
open my $fh, '>:utf8', $new_file or do {
warn "Could not open $new_file: $!\n";
next;
};

print {$fh} $mt->render_file($file, { time => $now->hms } );
}

现在您已了解Mojo模板的所有内容,您可以处理完整的目录以启动新项目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use File::Find qw(find);

use v5.14;
use Mojo::Template;

my $mt = Mojo::Template->new->vars(1);

use Time::Piece;
my $now = localtime;

my $wanted = sub {
return unless /\.ep\z/;
my $new_file = $File::Find::name =~ s/\.ep\z//r;
open my $fh, '>:utf8', $new_file or do {
warn "Could not open $new_file: $!\n";
next;
};

print {$fh} $mt->render_file(
$File::Find::name,
{ time => $now->hms }
);
};

find( $wanted, @ARGV );

就是这样。您的$wanted子例程可以更复杂,将熟文件放在不同的目录中,跳过目录,以及许多其他内容。你甚至不需要使用File::Find ; 我喜欢它,因为它带有Perl。一些聪明的使用Mojo::FileMojo::Collection也可以做到这一点。其余的复杂性来自您想要应用它的特定情况。