summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2012-10-03 16:20:14 -0500
committerJesse Luehrs <doy@tozt.net>2012-10-03 16:20:14 -0500
commit8d8d169d9e30784474856a9b43c43cf21a3d6a91 (patch)
treea96a6c6900dd9732e97230d626256a3e6f7b1a94
parentb6b1bd1936ea207c74ecf0993bd3b7c55c71ec57 (diff)
downloadtext-handlebars-8d8d169d9e30784474856a9b43c43cf21a3d6a91.tar.gz
text-handlebars-8d8d169d9e30784474856a9b43c43cf21a3d6a91.zip
make section lambdas work
-rw-r--r--lib/Text/Handlebars.pm7
-rw-r--r--lib/Text/Xslate/Syntax/Handlebars.pm92
-rw-r--r--t/mustache-spec.t3
-rw-r--r--t/mustache.t11
4 files changed, 89 insertions, 24 deletions
diff --git a/lib/Text/Handlebars.pm b/lib/Text/Handlebars.pm
index fa9e32c..c9a2e18 100644
--- a/lib/Text/Handlebars.pm
+++ b/lib/Text/Handlebars.pm
@@ -72,8 +72,11 @@ sub _register_builtin_methods {
weaken(my $weakself = $self);
$funcs->{'(run_code)'} = sub {
- my ($code, $vars) = @_;
- return $self->render_string($code->(), $vars);
+ my ($code, $vars, $open_tag, $close_tag, @args) = @_;
+ my $to_render = $code->(@args);
+ $to_render = "{{= $open_tag $close_tag =}}$to_render"
+ if defined($open_tag) && defined($close_tag) && $close_tag ne '}}';
+ return $self->render_string($to_render, $vars);
};
}
diff --git a/lib/Text/Xslate/Syntax/Handlebars.pm b/lib/Text/Xslate/Syntax/Handlebars.pm
index 70e6506..6ec5769 100644
--- a/lib/Text/Xslate/Syntax/Handlebars.pm
+++ b/lib/Text/Xslate/Syntax/Handlebars.pm
@@ -29,6 +29,9 @@ sub split_tags {
my @chunks;
+ my @raw_text;
+ my @delimiters;
+
my $close_tag;
my $standalone = 1;
while ($input) {
@@ -49,6 +52,22 @@ sub split_tags {
$input =~ s/\A\Q$close_tag//
or die "Oops!";
+ my @extra;
+ if ($code =~ m{^/}) {
+ push @extra, pop @raw_text;
+ push @extra, pop @delimiters;
+ if (@raw_text) {
+ $raw_text[-1] .= $extra[0];
+ }
+ }
+ if (@raw_text) {
+ $raw_text[-1] .= $tag_start . $code . $tag_end;
+ }
+ if ($code =~ m{^[#^]}) {
+ push @raw_text, '';
+ push @delimiters, [$tag_start, $tag_end];
+ }
+
my $autochomp = $code =~ m{^[!#^/=]};
if ($code =~ s/^=\s*([^\s]+)\s+([^\s]+)\s*=$//) {
@@ -70,7 +89,8 @@ sub split_tags {
if (length($code)) {
push @chunks, [
($close_tag eq '}}}' ? 'raw_code' : 'code'),
- $code
+ $code,
+ @extra,
];
}
@@ -92,12 +112,17 @@ sub split_tags {
my $text = $1;
if (length($text)) {
push @chunks, [ text => $text ];
+
if ($standalone) {
$standalone = $text =~ /(?:^|\n)\s*$/;
}
else {
$standalone = $text =~ /\n\s*$/;
}
+
+ if (@raw_text) {
+ $raw_text[-1] .= $text;
+ }
}
}
else {
@@ -126,14 +151,24 @@ sub preprocess {
my $code = '';
for my $chunk (@chunks) {
- my ($type, $content) = @$chunk;
+ my ($type, $content, $raw_text, $delimiters) = @$chunk;
if ($type eq 'text') {
$content =~ s/(["\\])/\\$1/g;
$code .= qq{print_raw "$content";\n}
if length($content);
}
elsif ($type eq 'code') {
- $code .= qq{$content;\n};
+ my $extra = '';
+ if (@$chunk > 2) {
+ $chunk->[2] =~ s/(["\\])/\\$1/g;
+ $chunk->[3][0] =~ s/(["\\])/\\$1/g;
+ $chunk->[3][1] =~ s/(["\\])/\\$1/g;
+
+ $extra = ' "'
+ . join('" "', $chunk->[2], @{ $chunk->[3] })
+ . '"';
+ }
+ $code .= qq{$content$extra;\n};
}
elsif ($type eq 'raw_code') {
$code .= qq{mark_raw $content;\n};
@@ -224,7 +259,11 @@ sub std_block {
my $name = $self->expression(0);
# variable lookups are parsed into a ternary expression, hence arity 'if'
- if ($name->arity ne 'if' && $name->arity ne 'field') {
+ if ($name->arity eq 'if') {
+ $name = $name->third;
+ }
+
+ if ($name->arity ne 'variable' && $name->arity ne 'field') {
$self->_unexpected("opening block name", $self->token);
}
$self->advance(';');
@@ -232,14 +271,27 @@ sub std_block {
my $body = $self->statements;
$self->advance('/');
- my $closing_name = $self->expression(0);
+ # 1 so that i pick up names and field accesses, but not literals
+ # closing tags are followed by a literal string containing their raw text
+ my $closing_name = $self->expression(1);
+ if ($closing_name->arity eq 'if') {
+ $closing_name = $closing_name->third;
+ }
- if ($closing_name->arity ne 'if' && $closing_name->arity ne 'field') {
+ if ($closing_name->arity ne 'variable' && $closing_name->arity ne 'field') {
$self->_unexpected("closing block name", $self->token);
}
if ($closing_name->id ne $name->id) { # XXX
$self->_unexpected('/' . $name->id, $self->token);
}
+
+ my $raw_text = $self->token;
+ $self->advance;
+ my $open_tag = $self->token;
+ $self->advance;
+ my $close_tag = $self->token;
+ $self->advance;
+
$self->advance(';');
my $iterations = $inverted
@@ -308,11 +360,24 @@ sub std_block {
),
];
- return $self->symbol('(for)')->clone(
- arity => 'for',
- first => $iterations,
- second => [$loop_var],
- third => $body_block,
+ return $self->make_ternary(
+ $self->call('(is_code)', $name->clone),
+ $self->print_raw(
+ $self->call(
+ '(run_code)',
+ $name->clone,
+ $self->symbol('(vars)')->clone(arity => 'vars'),
+ $open_tag->clone,
+ $close_tag->clone,
+ $raw_text->clone,
+ ),
+ ),
+ $self->symbol('(for)')->clone(
+ arity => 'for',
+ first => $iterations,
+ second => [$loop_var],
+ third => $body_block,
+ ),
);
}
@@ -378,6 +443,11 @@ sub make_ternary {
);
}
+sub print_raw {
+ my $self = shift;
+ return $self->print(@_)->clone(id => 'print_raw');
+}
+
if (0) {
require Devel::STDERR::Indent;
my @stack;
diff --git a/t/mustache-spec.t b/t/mustache-spec.t
index 8ee1c10..a97cb10 100644
--- a/t/mustache-spec.t
+++ b/t/mustache-spec.t
@@ -16,9 +16,6 @@ for my $file (dir('t', 'mustache-spec', 'specs')->children) {
local $TODO = "unimplemented"
if $file->basename eq 'delimiters.json'
&& $test->{name} =~ /partial/i;
- local ($TODO, $SIG{__WARN__}) = ("unimplemented", sub { })
- if $file->basename eq '~lambdas.json'
- && $test->{name} =~ /section/i;
render_ok(
$test->{template},
diff --git a/t/mustache.t b/t/mustache.t
index 6da8dd8..bbd9227 100644
--- a/t/mustache.t
+++ b/t/mustache.t
@@ -87,7 +87,6 @@ RENDERED
"section with non-empty list"
);
-{ local $TODO = "unimplemented"; local $SIG{__WARN__} = sub { };
render_ok(
<<'TEMPLATE',
{{#wrapped}}
@@ -97,12 +96,9 @@ TEMPLATE
{
name => 'Willy',
wrapped => sub {
- return sub {
- my ($text) = @_;
- return '<b>'
- . Text::Handlebars->new->render_string($text) # XXX
- . '</b>';
- };
+ my ($text) = @_;
+ chomp($text);
+ return "<b>$text</b>\n";
},
},
<<'RENDERED',
@@ -110,7 +106,6 @@ TEMPLATE
RENDERED
"lambdas"
);
-}
render_ok(
<<'TEMPLATE',