package Text::Handlebars;
use strict;
use warnings;
# ABSTRACT: http://handlebarsjs.com/ for Text::Xslate
use Text::Xslate 1.6000;
use base 'Text::Xslate';
use Scalar::Util 'weaken';
use Try::Tiny;
=head1 SYNOPSIS
use Text::Handlebars;
my $handlebars = Text::Handlebars->new(
helpers => {
fullName => sub {
my ($context, $person) = @_;
return $person->{firstName}
. ' '
. $person->{lastName};
},
},
);
my $vars = {
author => { firstName => 'Alan', lastName => 'Johnson' },
body => "I Love Handlebars",
comments => [
author => { firstName => 'Yehuda', lastName => 'Katz' },
body => "Me too!",
],
};
say $handlebars->render_string(<<'TEMPLATE', $vars);
By {{fullName author}}
{{body}}
Comments
{{#each comments}}
By {{fullName author}}
{{body}}
{{/each}}
TEMPLATE
produces
By Alan Johnson
I Love Handlebars
Comments
By Yehuda Katz
Me Too!
=head1 DESCRIPTION
This module subclasses L to provide a parser for
L templates. In most ways, this module
functions identically to Text::Xslate, except that it parses Handlebars
templates instead.
Text::Handlebars accepts an additional constructor parameter of C to
define Handlebars-style helper functions. Standard helpers are identical to
functions defined with the C parameter, except that they receive the
current context implicitly as the first parameter (since perl doesn't have an
implicit C parameter). Block helpers also receive the context as the
first parameter, and they also receive the C parameter as a hashref.
As an example:
sub {
my ($context, $items, $options) = @_;
my $out = "";
for my $item (@$items) {
$out .= "- " . $options->{fn}->($item) . "
";
}
return $out . "
\n";
},
defines a simple block helper to generate a C<< >> list.
Text::Handlebars also overrides C and C to allow using
any type of data (not just hashrefs) as a context (so rendering a template
consisting of only C<{{.}}> works properly).
=cut
sub default_helpers {
my $class = shift;
return {
with => sub {
my ($context, $new_context, $options) = @_;
return $options->{fn}->($new_context);
},
each => sub {
my ($context, $list, $options) = @_;
return join '', map { $options->{fn}->($_) } @$list;
},
if => sub {
my ($context, $conditional, $options) = @_;
return $conditional
? $options->{fn}->($context)
: $options->{inverse}->($context);
},
unless => sub {
my ($context, $conditional, $options) = @_;
return $conditional
? $options->{inverse}->($context)
: $options->{fn}->($context);
},
};
}
sub default_functions {
my $class = shift;
return {
%{ $class->SUPER::default_functions(@_) },
%{ $class->default_helpers },
};
}
sub options {
my $class = shift;
my $options = $class->SUPER::options(@_);
$options->{compiler} = 'Text::Handlebars::Compiler';
$options->{helpers} = {};
return $options;
}
sub _register_builtin_methods {
my $self = shift;
my ($funcs) = @_;
weaken(my $weakself = $self);
$funcs->{'(render_string)'} = sub {
my ($to_render, $vars) = @_;
return $weakself->render_string($to_render, $vars);
};
$funcs->{'(make_block_helper)'} = sub {
my ($vars, $code, $raw_text, $else_raw_text, $hash) = @_;
my $options = {};
$options->{fn} = sub {
my ($new_vars) = @_;
$new_vars = {
%{ canonicalize_vars($new_vars) },
'..' => $vars,
};
return $weakself->render_string($raw_text, $new_vars);
};
$options->{inverse} = sub {
my ($new_vars) = @_;
$new_vars = {
%{ canonicalize_vars($new_vars) },
'..' => $vars,
};
return $weakself->render_string($else_raw_text, $new_vars);
};
$options->{hash} = $hash;
return sub { $code->(@_, $options); };
};
for my $helper (keys %{ $self->{helpers} }) {
$funcs->{$helper} = $self->{helpers}{$helper};
}
}
sub _compiler {
my $self = shift;
if (!ref($self->{compiler})) {
my $compiler = $self->SUPER::_compiler(@_);
$compiler->define_helper(keys %{ $self->{helpers} });
$compiler->define_helper(keys %{ $self->default_helpers });
return $compiler;
}
else {
return $self->SUPER::_compiler(@_);
}
}
sub render_string {
my $self = shift;
my ($string, $vars) = @_;
return $self->SUPER::render_string($string, canonicalize_vars($vars));
}
sub render {
my $self = shift;
my ($name, $vars) = @_;
return $self->SUPER::render($name, canonicalize_vars($vars));
}
sub canonicalize_vars {
my ($vars) = @_;
if (ref($vars) && ref($vars) eq 'HASH') {
return $vars;
}
else {
return { '.' => $vars };
}
}
=head1 BUGS/CAVEATS
=over 4
=item *
The auto-indenting behavior for partials is not yet implemented, due to
limitations in Text::Xslate.
=item *
The C parameter for C<@foo> variables when calling
C<< $options->{fn}->() >> is not supported, because I don't understand its
purpose. If someone wants this functionality, feel free to let me know, and
tell me why.
=back
Please report any bugs through RT: email
C, or browse to
L.
=head1 SEE ALSO
L
L
=head1 SUPPORT
You can find this documentation for this module with the perldoc command.
perldoc Text::Handlebars
You can also look for information at:
=over 4
=item * AnnoCPAN: Annotated CPAN documentation
L
=item * CPAN Ratings
L
=item * RT: CPAN's request tracker
L
=item * Search CPAN
L
=back
=for Pod::Coverage
default_helpers
default_functions
options
render_string
render
canonicalize_vars
=cut
1;