ETOOBUSY 🚀 minimal blogging for the impatient
Adding functions in Template::Perlish
TL;DR
Notes on “adding” functions for a template.
As any average Perl hacker, I passed through that phase where I had the urge to produce my own templating system.
There was a reason - there’s always a reason, right?!? - in that I wanted a single-file module that I could easily embed with my programs, and nothing at that time ticked all checkboxes.
This marked the start of Template::Perlish. It’s a lazy approach to adding business logic, because it’s a sort of poor man’s PHP where templates are a mix of data and Perl code.
It’s obviously not for the web, but it’s quite handy for situations where there’s full control over both the templates and the data fed into them. I have used it since it was born and I never regret using it when the need arises. By the way, it’s the module behind teepee.
Templates have the full power of Perl at their disposal. As an example, I recently wrote about ActiveDirectory password encoding in Perl and shell, which might be used like this in a template:
dn: CN=TestUser,DC=testdomain,DC=com
changetype: modify
replace: unicodePwd
unicodePwd:: [%=
use Encode 'encode';
use MIME::Base64 'encode_base64';
my $password = 'newPassword';
encode_base64(encode('UTF-16LE', qq{"$password"}), '');
%]
This admittedly sucks, but it can be written in a more readable way:
[%
sub encode_password {
require Encode;
require MIME::Base64;
my $password = shift;
return MIME::Base64::encode_base64(
Encode::encode('UTF-16LE', qq{"$password"}),
'', # no newlines, please!
);
}
%]
dn: CN=TestUser,DC=testdomain,DC=com
changetype: modify
replace: unicodePwd
unicodePwd:: [%= encode_password('newPassword') %]
The natural evolution of this is that the sub is put elsewhere, like a module:
[%
use MyUtils qw< encode_password >;
%]
dn: CN=TestUser,DC=testdomain,DC=com
changetype: modify
replace: unicodePwd
unicodePwd:: [%= encode_password('newPassword') %]
Another approach might be to inject the encode_password
function
directly from the Perl program that uses Template::Perlish for
the rendering. This might e.g. be done like this:
use v5.24;
use warnings;
use Template::Perlish 'render';
my $template = <<'END';
dn: CN=TestUser,DC=testdomain,DC=com
changetype: modify
replace: unicodePwd
unicodePwd:: [%= encode_password(V 'password') %]
END
sub render_with_benefits {
package Template::Perlish;
no warnings 'once';
local *encode_password = sub {
require Encode;
require MIME::Base64;
my $password = shift;
return MIME::Base64::encode_base64(
Encode::encode('UTF-16LE', qq{"$password"}),
'', # no newlines, please!
);
};
return render(@_);
}
say render_with_benefits($template, {password => 'newPassword'});
Some takeaways:
- at the moment, all templates are rendered within
Template::Perlish
as the current package. This is why we put thepackage ...
line inside the sub; - we use
local
to avoid polluting theTemplate::Perlish
namespace for other templates that do not need to use that new function. - the
no warnings...
is to silence the check by Perl while settingencode_password
. It might be done differently.
Stay safe and rendered!