summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2012-10-03 15:05:25 -0500
committerJesse Luehrs <doy@tozt.net>2012-10-03 15:08:29 -0500
commitb6b1bd1936ea207c74ecf0993bd3b7c55c71ec57 (patch)
tree6c67d41ca8ceedb1daeecce1fec877a46108e7e1
parentbbec479a424eda0bc48250c118aaad85ddb6ee00 (diff)
downloadtext-handlebars-b6b1bd1936ea207c74ecf0993bd3b7c55c71ec57.tar.gz
text-handlebars-b6b1bd1936ea207c74ecf0993bd3b7c55c71ec57.zip
make basic lambdas work (not block lambdas yet)
-rw-r--r--lib/Text/Handlebars.pm15
-rw-r--r--lib/Text/Xslate/Syntax/Handlebars.pm22
-rw-r--r--t/mustache-spec.t25
3 files changed, 58 insertions, 4 deletions
diff --git a/lib/Text/Handlebars.pm b/lib/Text/Handlebars.pm
index 30a769c..fa9e32c 100644
--- a/lib/Text/Handlebars.pm
+++ b/lib/Text/Handlebars.pm
@@ -22,6 +22,10 @@ sub default_functions {
my ($length) = @_;
return [(undef) x $length];
},
+ '(is_code)' => sub {
+ my ($val) = @_;
+ return ref($val) && ref($val) eq 'CODE';
+ },
'(new_vars_for)' => sub {
my ($vars, $value, $i) = @_;
$i = 0 unless defined $i; # XXX
@@ -62,4 +66,15 @@ sub options {
return $options;
}
+sub _register_builtin_methods {
+ my $self = shift;
+ my ($funcs) = @_;
+
+ weaken(my $weakself = $self);
+ $funcs->{'(run_code)'} = sub {
+ my ($code, $vars) = @_;
+ return $self->render_string($code->(), $vars);
+ };
+}
+
1;
diff --git a/lib/Text/Xslate/Syntax/Handlebars.pm b/lib/Text/Xslate/Syntax/Handlebars.pm
index d8f2f9a..70e6506 100644
--- a/lib/Text/Xslate/Syntax/Handlebars.pm
+++ b/lib/Text/Xslate/Syntax/Handlebars.pm
@@ -181,6 +181,23 @@ sub nud_name {
}
}
+sub nud_variable {
+ my $self = shift;
+ my ($symbol) = @_;
+
+ my $var = $self->SUPER::nud_variable(@_);
+
+ return $self->make_ternary(
+ $self->call('(is_code)', $var->clone),
+ $self->call(
+ '(run_code)',
+ $var->clone,
+ $self->symbol('(vars)')->clone(arity => 'vars'),
+ ),
+ $var,
+ );
+}
+
sub led_dot {
my $self = shift;
my ($symbol, $left) = @_;
@@ -206,7 +223,8 @@ sub std_block {
my $inverted = $symbol->id eq '^';
my $name = $self->expression(0);
- if ($name->arity ne 'variable' && $name->arity ne 'field') {
+ # variable lookups are parsed into a ternary expression, hence arity 'if'
+ if ($name->arity ne 'if' && $name->arity ne 'field') {
$self->_unexpected("opening block name", $self->token);
}
$self->advance(';');
@@ -216,7 +234,7 @@ sub std_block {
$self->advance('/');
my $closing_name = $self->expression(0);
- if ($closing_name->arity ne 'variable' && $closing_name->arity ne 'field') {
+ if ($closing_name->arity ne 'if' && $closing_name->arity ne 'field') {
$self->_unexpected("closing block name", $self->token);
}
if ($closing_name->id ne $name->id) { # XXX
diff --git a/t/mustache-spec.t b/t/mustache-spec.t
index 3713abc..8ee1c10 100644
--- a/t/mustache-spec.t
+++ b/t/mustache-spec.t
@@ -9,7 +9,6 @@ use Test::Requires 'JSON', 'Path::Class';
for my $file (dir('t', 'mustache-spec', 'specs')->children) {
next unless $file =~ /\.json$/;
- next if $file->basename =~ /^~/; # for now
next if $file->basename =~ /partials/;
my $tests = decode_json($file->slurp);
note("running " . $file->basename . " tests");
@@ -17,14 +16,36 @@ 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},
- $test->{data},
+ fix_data($test->{data}),
$test->{expected},
"$test->{name}: $test->{desc}"
);
}
}
+sub fix_data {
+ my ($data) = @_;
+
+ if (ref($data) eq 'HASH') {
+ if ($data->{__tag__} && $data->{__tag__} eq 'code') {
+ return eval $data->{perl};
+ }
+ else {
+ return { map { $_ => fix_data($data->{$_}) } keys %$data };
+ }
+ }
+ elsif (ref($data) eq 'ARRAY') {
+ return [ map { fix_data($_) } @$data ];
+ }
+ else {
+ return $data;
+ }
+}
+
done_testing;