#ABSTRACT: Pure Perl 5 template engine for Dancer package Dancer::Template::Simple; { $Dancer::Template::Simple::VERSION = '1.9999_02'; } use strict; use warnings; use Carp; use Moo; use Dancer::FileUtils 'read_file_content'; with 'Dancer::Core::Role::Template'; has start_tag => ( is => 'rw', default => sub {'<%'}, ); has stop_tag => ( is => 'rw', default => sub {'%>'}, ); sub _build_name {'Simple'} sub BUILD { my $self = shift; my $settings = $self->config; $settings->{$_} and $self->$_($settings->{$_}) for qw/ start_tag stop_tag /; } sub render { my ($self, $template, $tokens) = @_; my $content; $content = read_file_content($template); $content = $self->parse_branches($content, $tokens); return $content; } sub parse_branches { my ($self, $content, $tokens) = @_; my ($start, $stop) = ($self->start_tag, $self->stop_tag); my @buffer; my $prefix = ""; my $should_bufferize = 1; my $bufferize_if_token = 0; # $content =~ s/\Q${start}\E(\S)/${start} $1/sg; # $content =~ s/(\S)\Q${stop}\E/$1 ${stop}/sg; # we get here a list of tokens without the start/stop tags my @full = split(/\Q$start\E\s*(.*?)\s*\Q$stop\E/, $content); # and here a list of tokens without variables my @flat = split(/\Q$start\E\s*.*?\s*\Q$stop\E/, $content); # eg: for 'foo=<% var %>' # @full = ('foo=', 'var') # @flat = ('foo=') my $flat_index = 0; my $full_index = 0; for my $word (@full) { # flat word, nothing to do if (defined $flat[$flat_index] && ($flat[$flat_index] eq $full[$full_index])) { push @buffer, $word if $should_bufferize; $flat_index++; $full_index++; next; } my @to_parse = ($word); @to_parse = split(/\s+/, $word) if $word =~ /\s+/; for my $w (@to_parse) { if ($w eq 'if') { $bufferize_if_token = 1; } elsif ($w eq 'else') { $should_bufferize = !$should_bufferize; } elsif ($w eq 'end') { $should_bufferize = 1; } elsif ($bufferize_if_token) { my $bool = _find_value_from_token_name($w, $tokens); $should_bufferize = _interpolate_value($bool) ? 1 : 0; $bufferize_if_token = 0; } elsif ($should_bufferize) { my $val = _interpolate_value(_find_value_from_token_name($w, $tokens)); push @buffer, $val; } } $full_index++; } return join "", @buffer; } sub _find_value_from_token_name { my ($key, $tokens) = @_; my $value = undef; my @elements = split /\./, $key; foreach my $e (@elements) { if (not defined $value) { $value = $tokens->{$e}; } elsif (ref($value) eq 'HASH') { $value = $value->{$e}; } elsif (ref($value)) { local $@; eval { $value = $value->$e }; $value = "" if $@; } } return $value; } sub _interpolate_value { my ($value) = @_; if (ref($value) eq 'CODE') { local $@; eval { $value = $value->() }; $value = "" if $@; } elsif (ref($value) eq 'ARRAY') { $value = "@{$value}"; } $value = "" if not defined $value; return $value; } 1; __END__ =pod =head1 NAME Dancer::Template::Simple - Pure Perl 5 template engine for Dancer =head1 VERSION version 1.9999_02 =head1 DESCRIPTION This template engine is provided as a default one for the Dancer micro framework. This template engine should be fine for development purposes but is not a powerful one, it's written in pure Perl and has no C bindings to accelerate the template processing. If you want to power an application with Dancer in production environment, it's strongly advised to switch to Dancer::Template::TemplateToolkit. =head1 SYNTAX A template written for Dancer::Template::Simple should be working just fine with Dancer::Template::TemplateToolkit. The opposite is not true though. =over 4 =item B<variables> To interpolate a variable in the template, use the following syntax: <% var1 %> If 'var1' exists in the tokens hash given, its value will be written there. =back =head1 SEE ALSO L<Dancer>, L<Dancer::Template> =head1 AUTHOR Dancer Core Developers =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2012 by Alexis Sukrieh. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut