Permalink
Browse files

Adding an (optional) render argument to lambdas.

This change also uncovered (and fixed) a bug
wherein references in the Template Cache were
being destroyed through inattention.
  • Loading branch information...
1 parent b67ae95 commit 89da5a6610d80d95b4d3a274e8546d9297609781 @pvande pvande committed Feb 2, 2011
Showing with 86 additions and 5 deletions.
  1. +10 −5 lib/Template/Mustache.pm
  2. +76 −0 t/lambdas_receive_render_helper.t
View
@@ -202,16 +202,19 @@ sub generate {
# except partial tags).
unless (@result) {
my ($type, $tag, $data) = @$_;
+ my $render = sub { $build->(shift, $data->[1]) };
+
my ($ctx, $value) = lookup($tag, @context) unless $type eq '>';
if ($type eq '{' || $type eq '&' || $type eq '') {
# Interpolation Tags
# If the value is a code reference, we should treat it
# according to Mustache's lambda rules. Specifically, we
- # should call the sub, render its contents against the current
+ # should call the sub (passing a "render" function as a
+ # convenience), render its contents against the current
# context, and cache the value (if possible).
if (ref $value eq 'CODE') {
- $value = $build->($value->());
+ $value = $build->($value->($render));
$ctx->{$tag} = $value if ref $ctx eq 'HASH';
}
# An empty `$type` represents an HTML escaped tag.
@@ -227,13 +230,15 @@ sub generate {
# * If the value is an array reference, the section is
# rendered once using each element of the array.
# * If the value is a code reference, the raw section string
- # is passed to the sub to be filtered before rendering.
+ # and a rendering function are passed to the sub; the return
+ # value is then automatically rendered.
# * Otherwise, the section is rendered using given value.
if (ref $value eq 'ARRAY') {
@result = map { $build->(@$data, $_) } @$value;
} elsif ($value) {
- $data->[0] = $value->($data->[0]) if ref $value eq 'CODE';
- @result = $build->(@$data, $value);
+ my @x = @$data;
+ $x[0] = $value->($x[0], $render) if ref $value eq 'CODE';
+ @result = $build->(@x, $value);
}
} elsif ($type eq '^') {
# Inverse Section Tags
@@ -0,0 +1,76 @@
+use Test::Mini::Unit;
+use Template::Mustache;
+
+case t::LambdasReceiveRenderHelper {
+ {
+ package t::LambdasReceiveRenderHelper::Mustache;
+ use base 'Template::Mustache';
+
+ sub name { sub { pop->('{{user}}') } }
+ sub obfuscated { sub { pop->('{{'.reverse(shift).'}}') } }
+ sub user { '({{logged_in_as}})' }
+ sub logged_in_as { 'Sam' }
+ }
+
+ case Interpolation {
+ setup {
+ $self->{tmpl} = 'I am {{name}}';
+ }
+
+ test from_hash {
+ my $data = {
+ name => sub { pop->('{{user}}') },
+ user => '({{logged_in_as}})',
+ logged_in_as => 'Sam',
+ };
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+
+ test from_class {
+ my $data = 't::LambdasReceiveRenderHelper::Mustache';
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+
+ test from_instance {
+ my $data = t::LambdasReceiveRenderHelper::Mustache->new();
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+ }
+
+ case SectionTags {
+ setup {
+ $self->{tmpl} = 'I am {{#obfuscated}}resu{{/obfuscated}}';
+ }
+
+ test from_hash {
+ my $data = {
+ obfuscated => sub { pop->('{{'.reverse(shift).'}}') },
+ user => '({{logged_in_as}})',
+ logged_in_as => 'Sam',
+ };
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+
+ test from_class {
+ my $data = 't::LambdasReceiveRenderHelper::Mustache';
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+
+ test from_instance {
+ my $data = t::LambdasReceiveRenderHelper::Mustache->new();
+
+ my $rendered = Template::Mustache->render($self->{tmpl}, $data);
+ assert_equal($rendered, 'I am (Sam)');
+ }
+ }
+}

0 comments on commit 89da5a6

Please sign in to comment.