use constant DEBUG_GET_PARMS => 0;
-our $VERSION = "1.027";
+our $VERSION = "1.028";
my %compile_cache;
Produce I<content> while I<condition> is true.
+=item *
+
+C<< <:.wrap I<name>, I<name>:I<value> ... :> >>
+
+Wrap content up until C<< <:.end wrap:> >> or end of file with the
+content from the file or macro I<name>.
+
=back
=head1 Special Variables
This is set to the names and values supplied in a C<wrap> request, so:
- <:= param.name :>
+ <:= params.name :>
is equivalent to:
use strict;
use Exporter qw(import);
-our $VERSION = "1.007";
+our $VERSION = "1.008";
sub _define_sequence {
my ($keys, $start) = @_;
_define_sequence(\@node_comp, 4);
my @node_with = qw(NODE_WITH_CONTENT NODE_WITH_END);
_define_sequence(\@node_with, 6);
-my @node_wrap = qw(NODE_WRAP_FILENAME NODE_WRAP_ARGS NODE_WRAP_CONTENT);
+my @node_wrap = qw(NODE_WRAP_FILENAME NODE_WRAP_ARGS NODE_WRAP_CONTENT NODE_WRAP_END);
_define_sequence(\@node_wrap, 4);
my @node_switch = qw(NODE_SWITCH_CASES NODE_SWITCH_END);
_define_sequence(\@node_switch, 5);
use strict;
use Squirrel::Template::Constants qw(:token :node);
-our $VERSION = "1.016";
+our $VERSION = "1.018";
use constant TOK => 0;
use constant TMPLT => 1;
}
}
+sub _parse_ext_wrap {
+ my ($self, $wrap) = @_;
+
+ my $content = $self->_parse_content;
+ my $end = $self->[TOK]->get;
+
+ # it's not really the filename (yet)
+ my $tokens = Squirrel::Template::Expr::Tokenizer->new($wrap->[NODE_WRAP_FILENAME]);
+
+ my @errors;
+ my $parser = Squirrel::Template::Expr::Parser->new;
+ my $name_expr;
+ unless (eval { $name_expr = $parser->parse_tokens($tokens); 1 }) {
+ return $self->_error($wrap, "Could not parse expression: ".$@->[1]);
+ }
+
+ my @result;
+ my $next = $tokens->get;
+ my @args;
+ if ($next->[0] eq 'op,') {
+ unless (eval {
+ while ($next->[0] eq 'op,') {
+ my $key;
+ my $value;
+ $key = $parser->parse_tokens($tokens);
+ my $colon = $tokens->get;
+ $colon->[0] eq 'op:'
+ or die [ error => "Expected : but found $colon->[0]" ];
+ $value = $parser->parse_tokens($tokens);
+ push @args, [ $key, $value ];
+ $next = $tokens->get;
+ }
+
+ if ($next->[0] ne 'eof') {
+ die [ error => "Expected , or eof but found $next->[0]" ];
+ }
+ 1;
+ }) {
+ return $self->_error($wrap, ref $@ ? $@->[0] : $@);
+ }
+ }
+ elsif ($next->[0] ne 'eof') {
+ push @errors, $self->_error($wrap, "Expected , or end of expression but found $next->[0]");
+ }
+
+ if ($end->[TOKEN_TYPE] eq 'end') {
+ if ($end->[TOKEN_END_TYPE] && $end->[TOKEN_END_TYPE] ne 'wrap') {
+ push @errors, $self->_error($end, "Expected '.end' or '.end wrap' for .wrap started $wrap->[TOKEN_FILENAME]:$wrap->[TOKEN_LINE] but found '.end $end->[TOKEN_END_TYPE]'");
+ }
+ }
+ elsif ($end->[TOKEN_TYPE] eq 'eof') {
+ $self->[TOK]->unget($end);
+ }
+ else {
+ $self->[TOK]->unget($end);
+ push @errors, $self->_error($end, "Expected '.end', '.end wrap' or eof for .wrap started $wrap->[TOKEN_FILENAME]:$wrap->[TOKEN_LINE] but found $end->[TOKEN_TYPE]");
+ $end = $self->_dummy($end, end => "");
+ }
+ $wrap->[NODE_WRAP_CONTENT] = $content;
+ $wrap->[NODE_WRAP_FILENAME] = $name_expr;
+ $wrap->[NODE_WRAP_ARGS] = \@args;
+ $wrap->[NODE_WRAP_END] = $end;
+
+ if (@errors) {
+ return $self->_comp($wrap, @errors);
+ }
+ else {
+ return $wrap;
+ }
+}
+
sub _parse_define {
my ($self, $define) = @_;
use Squirrel::Template::Constants qw(:node);
use Scalar::Util ();
-our $VERSION = "1.023";
+our $VERSION = "1.024";
use constant ACTS => 0;
use constant TMPLT => 1;
return ( @errors, @result );
}
+sub _process_ext_wrap {
+ my ($self, $node) = @_;
+
+ my ($filename, $args, $content) =
+ @{$node}[NODE_WRAP_FILENAME, NODE_WRAP_ARGS, NODE_WRAP_CONTENT];
+
+ my %args;
+ my @result;
+ my @errors;
+ my $name;
+ if (eval {
+ $name = $self->[EVAL]->process($filename);
+ for my $arg (@$args) {
+ my $key = $self->[EVAL]->process($arg->[0]);
+ my $value = $self->[EVAL]->process($arg->[1]);
+ $args{$key} = $value;
+ }
+ 1;
+ }) {
+ my $ctx = ".wrap '$name' from $node->[NODE_FILENAME]:$node->[NODE_LINE]";
+ if ($self->[TMPLT]->start_wrap(\%args)) {
+
+ my $parsed = $self->[TMPLT]->get_macro($name);
+ if (!$parsed) {
+ ($parsed, my $message) = $self->[TMPLT]->parse_file($name);
+ unless ($parsed) {
+ $self->[TMPLT]->trace_noimpl("call:$node->[NODE_FILENAME]:$node->[NODE_LINE]:$message\n");
+ push @result, $self->_error($node, "Loading wrap: $message");
+ }
+ }
+
+ if ($parsed) {
+ my $proc = __PACKAGE__->new($self->[ACTS], $self->[TMPLT],
+ sub { $self->process($content) });
+ push @result, $proc->process($parsed);
+ }
+ $self->[TMPLT]->end_wrap;
+ }
+ else {
+ push @result, $self->_error($node, "Starting wrap: too many levels?");
+ }
+ }
+ else {
+ @result =
+ (
+ $node->[NODE_ORIG],
+ $self->process($node->[NODE_WRAP_CONTENT]),
+ $node->[NODE_WRAP_END][NODE_ORIG],
+ );
+ }
+
+ return ( @errors, @result );
+}
+
sub _process_wraphere {
my ($self, $node) = @_;
use strict;
use Squirrel::Template::Constants qw(:token);
-our $VERSION = "1.013";
+our $VERSION = "1.014";
use constant QUEUE => 0;
use constant TEXT => 1;
elsif ($body =~ /\A\.call\s+(\S.*)?\z/s) {
push @$queue, [ call => $tag, $line, $name, $1 ];
}
+ elsif ($body =~ /\A\.wrap\s+(\S.*)?\z/s) {
+ push @$queue, [ ext_wrap => $tag, $line, $name, $1 ];
+ }
elsif ($body =~ /\A\.iterateover\s+(\S.*)\z/s) {
push @$queue, [ iterateover => $tag, $line, $name, $1 ];
}
#!perl -w
# Basic tests for Squirrel::Template
use strict;
-use Test::More tests => 180;
+use Test::More tests => 184;
use HTML::Entities;
sub template_test($$$$;$$);
abc
OUTPUT
- template_test(<<TEMPLATE, <<OUTPUT, "wrap", \%acts, "both");
+ template_test(<<TEMPLATE, <<OUTPUT, "wrap more", \%acts, "both");
Before
<:wrap wraptest.tmpl title=>[cat "foo " [str]], menu => 1, showtitle => "abc" -:>
Alpha
before
* wrap here without being wrapped *
after
+OUTPUT
+
+ template_test(<<TEMPLATE, <<OUTPUT, ".wrap simple", \%acts, "in", \%vars);
+<:.wrap "wraptest.tmpl", "title": "foo " _ str, "menu": 1, "showtitle":"abc" :>Alpha
+<:param menu:>
+<:param showtitle:>
+<:= params.showtitle :>
+TEMPLATE
+<title>foo ABC</title>
+Alpha
+1
+abc
+abc
+OUTPUT
+
+ template_test(<<TEMPLATE, <<OUTPUT, ".wrap unknown", \%acts, "both");
+<:.wrap "unknown.tmpl":>
+Body
+TEMPLATE
+* Loading wrap: File unknown.tmpl not found *
+OUTPUT
+
+ template_test(<<TEMPLATE, <<OUTPUT, ".wrap recursive", \%acts, "both", \%vars);
+<:.wrap "wrapself.tmpl", "title":"foo " _ str, "menu":1, "showtitle":"abc" :>Alpha
+<:= params.menu :>
+<:= params.showtitle :>
+TEMPLATE
+* Error starting wrap: Too many levels of wrap for 'wrapself.tmpl' *<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+<title>foo ABC</title>
+Alpha
+1
+abc
+OUTPUT
+
+ template_test(<<TEMPLATE, <<OUTPUT, ".wrap more", \%acts, "both", \%vars);
+Before
+<:.wrap "wraptest.tmpl", "title":"foo " _ str, "menu":1, "showtitle":"abc" -:>
+Alpha
+<:= params.menu:>
+<:= params.showtitle:>
+<:-.end wrap-:>
+After
+TEMPLATE
+Before
+<title>foo ABC</title>
+Alpha
+1
+abc
+After
OUTPUT
# undefined iterator - replacement should happen on the inside