package Solution::Tag::Include;
{ $Solution::Tag::Include::VERSION = 'v1.0.0' }
require Template::Liquid::Error;
require Template::Liquid::Utility;
use File::Spec;
use base 'Template::Liquid::Tag';
my $base_dir;
sub import {
$base_dir = $_[1] ? $_[1] : '_includes/';
Template::Liquid::register_tag('include');
}
sub new {
my ($class, $args) = @_;
raise Template::Liquid::Error {type => 'Context',
message => 'Missing template argument',
fatal => 1
}
if !defined $args->{'template'};
raise Template::Liquid::Error {type => 'Context',
message => 'Missing parent argument',
fatal => 1
}
if !defined $args->{'parent'};
raise Template::Liquid::Error {
type => 'Syntax',
message => 'Missing argument list in ' . $args->{'markup'},
fatal => 1
}
if !defined $args->{'attrs'};
return
bless {name => 'inc-' . $args->{'attrs'},
file => $args->{'attrs'},
parent => $args->{'parent'},
template => $args->{'template'},
tag_name => $args->{'tag_name'},
markup => $args->{'markup'},
}, $class;
}
sub render {
my ($s) = @_;
my $file = $s->{template}{context}->resolve($s->{'file'});
raise Template::Liquid::Error {
type => 'Argument',
message => 'Error: Missing or undefined argument passed to include'
}
&& return
if !defined $file;
if ( $file !~ m[^[\w\\/\.-_]+$]io
|| $file =~ m[\.[\\/]]o
|| $file =~ m[[//\\]\.]o)
{ raise Template::Liquid::ArgumentError sprintf
q[Error: Include file '%s' contains invalid characters or sequiences],
$file && return;
}
$file = File::Spec->catdir(
# $s->{template}{context}->registers->{'site'}->source,
$base_dir,
$file
);
raise Template::Liquid::Error {
type => 'I/O',
message => sprintf 'Error: Included file %s not found',
$file
}
&& return
if !-f $file;
open(my ($FH), '<', $file)
|| raise Template::Liquid::FileSystemError {
type => 'I/O',
message => sprintf 'Error: Cannot include file %s: %s',
$file, $!
}
&& return;
sysread($FH, my ($DATA), -s $FH) == -s $FH
|| raise Template::Liquid::Error {
type => 'I/O',
message => sprintf
'Error: Cannot include file %s (Failed to read %d bytes): %s',
$file, -s $FH, $!
}
&& return;
my $partial = Template::Liquid->parse($DATA);
$partial->{'context'} = $s->{template}{context};
my $return = $partial->{context}->stack(sub { $partial->render(); });
return $return;
}
1;
=pod
=head1 NAME
Solution::Tag::Include - Include another file (Functioning Custom Tag Example)
=head1 Synopsis
{% include 'comments.inc' %}
=head1 Description
This is a demonstration of
L<extending Template::Liquid|Template::Liquid/"Extending Template::Liquid">.
If you find yourself using the same snippet of code or text in several
templates, you may consider making the snippet an include.
You include static filenames...
use Template::Liquid;
use Solution::Tag::Include;
Template::Liquid->parse("{%include 'my.inc'%}")->render();
...or 'dynamic' filenames (for example, based on a variable)...
use Template::Liquid;
use Solution::Tag::Include;
Template::Liquid->parse('{%include inc%}')->render(inc => 'my.inc');
=head1 Notes
The default directory searched for includes is C<./_includes/> but this can be
changed in the include statement...
use Solution::Tag::Include '~/my_site/templates/includes';
This mimics Jekyll's include statement and was a 15m hack so it's subject to
change ...and may be completly broken.
=head1 See Also
Liquid for Designers: http://wiki.github.com/tobi/liquid/liquid-for-designers
L<Template::Liquid|Template::Liquid/"Extending Template::Liquid">'s section on
custom tags.
=head1 Author
Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/
=head1 License and Legal
Copyright (C) 2009-2012 by Sanko Robinson E<lt>sanko@cpan.orgE<gt>
This program is free software; you can redistribute it and/or modify it under
the terms of The Artistic License 2.0. See the F<LICENSE> file included with
this distribution or http://www.perlfoundation.org/artistic_license_2_0. For
clarification, see http://www.perlfoundation.org/artistic_2_0_notes.
When separated from the distribution, all original POD documentation is
covered by the Creative Commons Attribution-Share Alike 3.0 License. See
http://creativecommons.org/licenses/by-sa/3.0/us/legalcode. For
clarification, see http://creativecommons.org/licenses/by-sa/3.0/us/.
=cut