package Text::Handlebars; use strict; use warnings; # ABSTRACT: http://handlebarsjs.com/ for Text::Xslate 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->{'(find_file)'} = sub { my ($filename) = @_; return $filename if try { $weakself->find_file($filename); 1 }; $filename .= $weakself->{suffix}; return $filename if try { $weakself->find_file($filename); 1 }; return 0; }; $funcs->{'(make_block_helper)'} = sub { my ($code, $raw_text, $else_raw_text, $hash) = @_; my $options = {}; $options->{fn} = sub { my ($new_vars) = @_; return $weakself->render_string($raw_text, $new_vars); }; $options->{inverse} = sub { my ($new_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) = @_; if (ref($vars) && ref($vars) eq 'HASH') { return $self->SUPER::render_string(@_); } else { return $self->SUPER::render_string($string, { '.' => $vars }); } } sub render { my $self = shift; my ($name, $vars) = @_; if (ref($vars) && ref($vars) eq 'HASH') { return $self->SUPER::render(@_); } else { return $self->SUPER::render($name, { '.' => $vars }); } } =head1 BUGS/CAVEATS =over 4 =item * The auto-indenting behavior for partials is not yet implemented, due to limitations in Text::Xslate. =item * Passing a new context to partials is not yet supported. =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 render_string =cut 1;