Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added experimental support for escaped tags to Mojo::Template
  • Loading branch information
kraih committed Aug 27, 2011
1 parent 0754a05 commit 5036e40
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 69 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,6 +1,7 @@
This file documents the revision history for Perl extension Mojolicious.

1.93 2011-08-26 00:00:00
- Added EXPERIMENTAL support for escaped tags to Mojo::Template.
- Improved documentation.
- Fixed small version detection bug in Mojo::Cookie.

Expand Down
136 changes: 77 additions & 59 deletions lib/Mojo/Template.pm
Expand Up @@ -21,6 +21,7 @@ has expression_mark => '=';
has line_start => '%';
has name => 'template';
has namespace => 'Mojo::Template::SandBox';
has replace_mark => '%';
has tag_start => '<%';
has tag_end => '%>';
has template => '';
Expand Down Expand Up @@ -196,25 +197,31 @@ sub interpret {
# "I am so smart! I am so smart! S-M-R-T! I mean S-M-A-R-T..."
sub parse {
my ($self, $tmpl) = @_;
$self->template($tmpl);

# Clean start
$self->template($tmpl);
delete $self->{tree};

# Tags
my $line_start = quotemeta $self->line_start;
my $tag_start = quotemeta $self->tag_start;
my $tag_end = quotemeta $self->tag_end;
my $cmnt = quotemeta $self->comment_mark;
my $escp = quotemeta $self->escape_mark;
my $expr = quotemeta $self->expression_mark;
my $trim = quotemeta $self->trim_mark;
my $capture_start = quotemeta $self->capture_start;
my $capture_end = quotemeta $self->capture_end;

# Mixed
# Token
my $raw_line_start = $self->line_start;
my $raw_tag_start = $self->tag_start;
my $raw_replace = $self->replace_mark;
my $line_start = quotemeta $raw_line_start;
my $tag_start = quotemeta $raw_tag_start;
my $tag_end = quotemeta $self->tag_end;
my $cmnt = quotemeta $self->comment_mark;
my $escp = quotemeta $self->escape_mark;
my $expr = quotemeta $self->expression_mark;
my $trim = quotemeta $self->trim_mark;
my $capture_start = quotemeta $self->capture_start;
my $capture_end = quotemeta $self->capture_end;
my $replace = quotemeta $raw_replace;

# Mixed line regex
my $mixed_re = qr/
(
$tag_start$replace # Replace
|
$tag_start$expr$escp\s*$capture_end # Escaped expression (end)
|
$tag_start$expr$escp # Escaped expression
Expand Down Expand Up @@ -243,28 +250,23 @@ sub parse {

# Capture end regex
my $capture_end_re = qr/
^(
$tag_start # Start
)
(?:
$expr # Expression
)?
(?:
$escp # Escaped expression
)?
^
($tag_start) # Start
(?:$expr)? # Expression
(?:$escp)? # Escaped expression
\s*$capture_end # (end)
/x;

# Tag end regex
my $end_re = qr/
^(
$capture_start\s*$trim$tag_end # Trim end (start)
)|(
$capture_start\s*$tag_end # End (start)
)|(
$trim$tag_end # Trim end
)|
$tag_end # End
^
($capture_start\s*$trim$tag_end) # Trim end (start)
|
($capture_start\s*$tag_end) # End (start)
|
($trim$tag_end) # Trim end
|
$tag_end # End
$
/x;

Expand All @@ -281,14 +283,17 @@ sub parse {
$
/x;

# Replace line regex
my $replace_re = qr/^(\s*)$line_start$replace/;

# Tokenize
my $state = 'text';
my @capture_token;
my $trimming = 0;
for my $line (split /\n/, $tmpl) {

# Perl line
if ($line =~ /$line_re/) {
if ($line !~ s/$replace_re/$1$raw_line_start/ && $line =~ $line_re) {
my @token = ();

# Capture end
Expand Down Expand Up @@ -316,19 +321,17 @@ sub parse {
next;
}

# Comment line, dummy token needed for line count
if ($line =~ /^\s*$line_start$cmnt(.+)?$/) {
next;
}
# Comment line
next if $line =~ /^\s*$line_start$cmnt(?:.+)?$/;

# Escaped line ending
if ($line =~ /(\\+)$/) {
my $len = length $1;

# Newline escaped
# Escaped newline
if ($len == 1) { $line =~ s/\\$// }

# Backslash escaped
# Escaped backslash
if ($len >= 2) {
$line =~ s/\\\\$/\\/;
$line .= "\n";
Expand All @@ -350,16 +353,14 @@ sub parse {
if $token =~ s/$capture_end_re/$1/;

# End
if ($state ne 'text' && $token =~ /$end_re/) {
if ($state ne 'text' && $token =~ $end_re) {

# Capture start
splice @token, -2, 0, 'cpst', undef if $1 || $2;

# Trim previous text
# Trim current line
if ($1 || $3) {
$trimming = 1;

# Trim current line
unless ($self->_trim_line(\@token, 4)) {

# Trim previous lines
Expand Down Expand Up @@ -395,6 +396,9 @@ sub parse {
# Value
else {

# Replace
$token = $raw_tag_start if $token eq "$raw_tag_start$raw_replace";

# Trimming
if ($trimming) {
if ($token =~ s/^(\s+)//) {
Expand All @@ -409,8 +413,6 @@ sub parse {

# Comments are ignored
next if $state eq 'cmnt';

# Store value
push @token, @capture_token, $state, $token;
@capture_token = ();
}
Expand Down Expand Up @@ -571,10 +573,14 @@ like that.
<%= Perl expression, replaced with result %>
<%== Perl expression, replaced with XML escaped result %>
<%# Comment, useful for debugging %>
<%% Replace with "<%" and keep parsing, useful for generating templates %>
% Perl line
%= Perl expression line, replaced with result
%== Perl expression line, replaced with XML escaped result
%# Comment line, useful for debugging
%% Replace with "%" and keep parsing, useful for generating templates
=head2 Automatic Escaping
Automatic escaping behavior can be reversed with the C<auto_escape>
attribute, this is the default in L<Mojolicious> C<.ep> templates for
Expand All @@ -589,10 +595,14 @@ L<Mojo::ByteStream> objects are always excluded from automatic escaping.
<%= b('<div>excluded!</div>') %>
=head2 Trimming
Whitespace characters around tags can be trimmed with a special tag ending.
<%= All whitespace characters around this expression will be trimmed =%>
=head2 Blocks
You can capture whole template blocks for reuse later with the C<begin> and
C<end> keywords.
Expand All @@ -603,6 +613,8 @@ C<end> keywords.
<%= $block->('Baerbel') %>
<%= $block->('Wolfgang') %>
=head2 Indenting
Perl lines can also be indented freely.
% my $block = begin
Expand All @@ -612,6 +624,8 @@ Perl lines can also be indented freely.
%= $block->('Baerbel')
%= $block->('Wolfgang')
=head2 Arguments
L<Mojo::Template> templates work just like Perl subs (actually they get
compiled to a Perl sub internally).
That means you can access arguments simply via C<@_>.
Expand All @@ -620,34 +634,27 @@ That means you can access arguments simply via C<@_>.
% my $x = shift;
test 123 <%= $foo %>
Note that you can't escape L<Mojo::Template> tags, instead we just replace
them if necessary.
=head2 More Escaping
my $mt = Mojo::Template->new;
$mt->line_start('@@');
$mt->tag_start('[@@');
$mt->tag_end('@@]');
$mt->expression_mark('&');
$mt->escape_mark('&');
my $output = $mt->render(<<'EOF', 23);
@@ my $i = shift;
<% no code just text [@@&& $i @@]
EOF
You can use escaped tags and lines to generate templates.
There is only one case that we can escape with a backslash, and that's a
newline at the end of a template line.
%% my $number = <%= 20 + 3 %>;
The number is <%%= $number %>
A newline can be escaped with a backslash.
This is <%= 23 * 3 %> a\
single line
If for some strange reason you absolutely need a backslash in front of a
newline you can escape the backslash with another backslash.
And a backslash in front of a newline can be escaped with another backslash.
% use Data::Dumper;
This will\\
result <%= Dumper {foo => 'bar'} %>\\
in multiple lines
=head2 Exceptions
Templates get compiled to Perl code internally, this can make debugging a bit
tricky.
But L<Mojo::Template> will return L<Mojo::Exception> objects that stringify
Expand All @@ -660,6 +667,8 @@ to error messages with context.
5: %= $i * 2
6: </body>
=head2 Caching
L<Mojo::Template> does not support caching by itself, but you can easily
build a wrapper around it.
Expand Down Expand Up @@ -787,6 +796,15 @@ Namespace used to compile templates, defaults to C<Mojo::Template::SandBox>.
Prepend Perl code to compiled template.
=head2 C<replace_mark>
my $replace_mark = $mt->replace_mark;
$mt = $mt->replace_mark('%');
Character used for escaping the start of a tag or line, defaults to C<%>.
<%% my $foo = 23; %>
=head2 C<tag_start>
my $tag_start = $mt->tag_start;
Expand Down
15 changes: 6 additions & 9 deletions lib/Mojolicious/Command/generate/app.pm
Expand Up @@ -43,9 +43,6 @@ EOF
$self->render_to_rel_file('static', "$name/public/index.html");

# Layout and Templates
$self->renderer->line_start('%%');
$self->renderer->tag_start('<%%');
$self->renderer->tag_end('%%>');
$self->render_to_rel_file('layout',
"$name/templates/layouts/default.html.ep");
$self->render_to_rel_file('welcome',
Expand Down Expand Up @@ -141,18 +138,18 @@ $t->get_ok('/welcome')->status_is(200)->content_like(qr/Mojolicious/i);
@@ layout
<!doctype html><html>
<head><title><%= title %></title></head>
<body><%= content %></body>
<head><title><%%= title %></title></head>
<body><%%= content %></body>
</html>
@@ welcome
% layout 'default';
% title 'Welcome';
<h2><%= $message %></h2>
%% layout 'default';
%% title 'Welcome';
<h2><%%= $message %></h2>
This page was generated from the template
"templates/example/welcome.html.ep" and the layout
"templates/layouts/default.html.ep",
<a href="<%== url_for %>">click here</a>
<a href="<%%== url_for %>">click here</a>
to reload the page or
<a href="/index.html">here</a>
to move forward to a static page.
Expand Down
2 changes: 2 additions & 0 deletions lib/Mojolicious/Guides/Rendering.pod
Expand Up @@ -59,10 +59,12 @@ set of special tags and line start characters.
<%= Perl expression, replaced with XML escaped result %>
<%== Perl expression, replaced with raw result %>
<%# Comment, useful for debugging %>
<%% Replace with "<%" and keep parsing, useful for generating templates %>
% Perl line
%= Perl expression line, replaced with XML escaped result
%== Perl expression line, replaced with raw result
%# Comment line, useful for debugging
%% Replace with "%" and keep parsing, useful for generating templates

The simplest form is used to insert raw Perl code.
Tags and lines work pretty much the same, but depending on context one will
Expand Down

0 comments on commit 5036e40

Please sign in to comment.