File Coverage

blib/lib/Template/Caribou/Files.pm
Criterion Covered Total %
statement 50 50 100.0
branch 5 8 62.5
condition 2 3 66.6
subroutine 17 17 100.0
pod n/a
total 74 78 94.8


line stmt bran cond sub pod time code
1             package Template::Caribou::Files;
2             our $AUTHORITY = 'cpan:YANICK';
3             #ABSTRACT: Role to load templates from files
4             $Template::Caribou::Files::VERSION = '1.2.1';
5              
6 5     5   6639 use strict;
  5         7  
  5         135  
7 5     5   17 use warnings;
  5         6  
  5         453  
8              
9 4     4   1626 use MooseX::Role::Parameterized;
  4         220557  
  4         16  
10              
11 4     4   98082 use Module::Runtime qw/ module_notional_filename /;
  4         6  
  4         33  
12 4     4   158 use Path::Tiny;
  4         6  
  4         192  
13 4     4   13 use Try::Tiny;
  4         4  
  4         210  
14              
15 4     4   18 use experimental 'postderef';
  4         4  
  4         31  
16              
17             parameter dirs => (
18             default => undef,
19             );
20              
21             parameter intro => (
22             default => sub { [] },
23             );
24              
25             sub _load_template_file {
26 7     7   509 my $self = shift;
27 7         10 my $target = shift;
28              
29 7 50       36 my( $name, $file ) = @_ == 2 ? @_ : ( undef, @_ );
30              
31 7         17 $file = path($file);
32              
33 7 50       89 unless( $name ) {
34 7         28 $name = $file->basename =~ s/\.bou//r;
35             }
36              
37 7   66     215 my $class = ref $target || $target;
38              
39 7         25 my $code = join "\n",
40             "package $class;",
41             $self->intro->@*,
42             "# line 1 ". $file,
43             $file->slurp;
44              
45 3     3   22 my $coderef = eval $code;
  3     3   8  
  5     2   75  
  3     2   6  
  2         256  
  2         11  
  2         2  
  2         24  
  2         11  
  2         3  
  2         190  
  7         1666  
46 7 50       907 die $@ if $@;
47              
48 7 100       45 Template::Caribou::Role::template( (ref $target ? ( $target->meta, $target ) : $target->meta), $name, $coderef );
49             };
50              
51              
52             sub _load_template_dir {
53 7     7   13 my ( $self, $target, $dir ) = @_;
54              
55 7         24 $dir = path($dir);
56              
57 7         202 Template::Caribou::Files::_load_template_file($self,$target,$_) for $dir->children( qr/\.bou$/ );
58             };
59              
60              
61             role {
62             my $p = shift;
63             my %arg = @_;
64              
65             has template_dirs => (
66             traits => [ 'Array' ],
67             isa => 'ArrayRef',
68             builder => '_build_template_dirs',
69             handles => {
70             all_template_dirs => 'elements',
71             add_template_dirs => 'push',
72             },
73             );
74              
75             my $intro = $p->intro;
76             has file_intro => (
77             is => 'ro',
78             default => sub { $intro },
79             );
80              
81             my $dirs = $p->dirs;
82              
83             unless ( $dirs ) {
84             my $name = $arg{consumer}->name;
85              
86             try {
87             my $path = path( $INC{ module_notional_filename( $name )} =~ s/\.pm$//r );
88             die unless $path->is_dir;
89             $dirs = [ $path ];
90             } catch {
91             die "can't find directory for module '$name'";
92             };
93             }
94              
95             # so that we can call the role many times,
96             # and the defaults will telescope into each other
97 5     5   59 sub _build_template_dirs { [] }
98              
99             around _build_template_dirs => sub {
100             my( $ref, $self ) = @_;
101              
102             return [ @{ $ref->($self) }, @$dirs ];
103             };
104              
105              
106             Template::Caribou::Files::_load_template_dir( $p, $arg{consumer}->name, $_) for @$dirs;
107              
108             method add_template_file => sub {
109 2     2   37 my( $self, $file ) = @_;
        2      
        2      
110 2         7 $file = path($file);
111              
112 2         58 Template::Caribou::Files::_load_template_file(
113             $p,
114             $self,
115             $file
116             );
117             };
118              
119              
120              
121              
122             };
123              
124              
125              
126             1;
127              
128             __END__
129              
130             =pod
131              
132             =encoding UTF-8
133              
134             =head1 NAME
135              
136             Template::Caribou::Files - Role to load templates from files
137              
138             =head1 VERSION
139              
140             version 1.2.1
141              
142             =head1 SYNOPSIS
143              
144             package MyTemplate;
145              
146             use Template::Caribou;
147              
148             with 'Template::Caribou::Files' => {
149             dirs => [ './my_templates/' ],
150             intro => [ 'use 5.10.0;' ],
151             };
152              
153             1;
154              
155             =head1 DESCRIPTION
156              
157             A Caribou class consuming the C<Template::Caribou::Files> role
158             will automatically import
159             all template files (i.e., all files with a C<.bou> extension) under the given directories.
160              
161             The names of the imported templates will be their path, relative to the
162             imported directories, without their extension. To take the example in the
163             L</SYNOPSIS>, if the content of C<my_templates/> is:
164              
165             ./foo.bou
166             ./bar.bou
167              
168             then the templates C<foo.bou> and C<bar.bou> will be created.
169              
170             The template files themselves will be eval'ed in the context of
171             the parent class/namespace, and must return a coderef. E.g.,
172              
173             # file ./foo.bou
174              
175             # should be done in the class declaration, but
176             # can be done here as well
177             use Template::Caribou::Tags::HTML ':all';
178              
179             # likewise, would be better if added to
180             # as a Template::Caribou::Files's intro
181             use experimental 'signatures';
182              
183             sub ($self) {
184             div {
185             say 'this is foo';
186             $self->bar;
187             }
188             }
189              
190             =head1 METHODS
191              
192             =head2 all_template_dirs
193              
194             Returns a list of all template directories loaded by the
195             class (directories included by parent classes included).
196              
197             =head2 file_intro
198              
199             Returns the arrayref of the intro lines added to the F<.bou>
200             templates.
201              
202             =head1 ROLE PARAMETERS
203              
204             =head2 dirs
205              
206             The array ref of directories to scan for templates.
207              
208             If not provided,
209             it defaults to the directory associated with the template class.
210             For example, for
211              
212             package MyTemplates::Foo;
213              
214             use Template::Caribou;
215              
216             with 'Template::Caribou::Files';
217              
218             1;
219              
220             located at F<lib/MyTemplates/Foo.pm>, the default directory
221             will be F<lib/MyTemplates/Foo/>.
222              
223             =head2 intro
224              
225             Arrayref of lines to add at the beginning of all F<.bou> templates.
226              
227             package MyTemplates::Foo;
228              
229             use Template::Caribou;
230              
231             with 'Template::Caribou::Files' => {
232             intro => [
233             q{ use 5.10.0; },
234             q{ use experimental 'signatures'; },
235             ];
236             };
237              
238             =head1 AUTHOR
239              
240             Yanick Champoux <yanick@cpan.org>
241              
242             =head1 COPYRIGHT AND LICENSE
243              
244             This software is copyright (c) 2017 by Yanick Champoux.
245              
246             This is free software; you can redistribute it and/or modify it under
247             the same terms as the Perl 5 programming language system itself.
248              
249             =cut