File Coverage

blib/lib/Template/Caribou/Role.pm
Criterion Covered Total %
statement 80 81 98.7
branch 13 18 72.2
condition 7 9 77.7
subroutine 25 25 100.0
pod 4 4 100.0
total 129 137 94.1


line stmt bran cond sub pod time code
1             package Template::Caribou::Role;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: Caribou core engine
4             $Template::Caribou::Role::VERSION = '1.2.2';
5              
6 18     18   257931 use 5.20.0;
  18         80  
7 18     18   125 use strict;
  18         53  
  18         537  
8 18     18   97 use warnings;
  18         29  
  18         1063  
9 18     18   122 no warnings qw/ uninitialized /;
  18         32  
  18         918  
10              
11 18     18   134 use Carp;
  18         38  
  18         1373  
12 18     18   8068 use Moose::Role;
  18         7977546  
  18         97  
13 18     18   133173 use Template::Caribou::Utils;
  18         90  
  18         275  
14              
15 18     18   20967 use Path::Tiny;
  18         288111  
  18         1613  
16              
17 18     18   7141 use Template::Caribou::Tags;
  18         86  
  18         508  
18              
19 18     18   7192 use List::AllUtils qw/ uniq any /;
  18         86144  
  18         1621  
20              
21 18     18   129 use Moose::Exporter;
  18         32  
  18         176  
22             Moose::Exporter->setup_import_methods(
23             as_is => [ 'template' ],
24             );
25              
26 18     18   1413 use experimental 'signatures';
  18         55  
  18         182  
27              
28             has indent => (
29             is => 'rw',
30             default => 1,
31             );
32              
33             has can_add_templates => (
34             is => 'rw',
35             );
36              
37             sub template {
38 19     19 1 758791 my $class = shift;
39              
40             # cute way to say $self might or might not be there
41 19         72 my( $coderef, $name, $self ) = reverse @_;
42              
43 19 100       85 if ( $self ) {
44 5         64 local $Carp::CarpLevel = 1;
45 5 100       256 croak "can only add templates from instances created via 'anon_instance' ",
46             "or with the attribute 'can_add_templates'" unless $self->can_add_templates;
47              
48 3         17 $class = $self->meta;
49             }
50              
51             carp "redefining '$name'"
52 17 50 66 361   366 if $class->can('get_all_method_names') and any { $name eq $_ } $class->get_all_method_names;
  361         34102  
53 17 50       297 carp "redefining '$name'" if $class->name->can($name);
54              
55              
56             $class->add_method( $name => sub {
57 16     16   10442 my( $self, @args ) = @_;
        16      
        13      
        13      
        8      
        8      
        8      
58 16 100       45 if( defined wantarray ) {
59 13         76 return $self->render( $coderef, @args );
60             }
61             else {
62             # void context
63 3         10 $self->render( $coderef, @args );
64 3         8 return;
65             }
66 17         140 });
67             }
68              
69              
70              
71 1     1 1 1626 sub anon_instance($class,@args) {
  1         3  
  1         2  
  1         45  
72 1         12 Class::MOP::Class
73             ->create_anon_class(superclasses => [ $class ])
74             ->new_object( can_add_templates => 1, @args);
75             }
76              
77             sub get_render {
78 111     111 1 264 my ( $self, $template, @args ) = @_;
79 111         186 local $Template::Caribou::IN_RENDER;
80 111         327 return $self->render($template,@args);
81             }
82              
83             sub render {
84 149     149 1 644862 my ( $self, $template, @args ) = @_;
85              
86             # 0.1 is true, and yet will round down to '0' for the first indentation
87 149   100     1279 local $Template::Caribou::TAG_INDENT_LEVEL
88             = $Template::Caribou::TAG_INDENT_LEVEL // 0.1 * !! $self->indent;
89              
90 149         615 my $output = $self->_render($template,@args);
91              
92             # if we are still within a render, we turn the string
93             # into an object to say "don't touch"
94 149 100       387 $output = Template::Caribou::String->new( $output )
95             if $Template::Caribou::IN_RENDER;
96              
97             # called in a void context and inside a template => print it
98 149 100       341 print ::RAW $output if $Template::Caribou::IN_RENDER;
99              
100 149         563 return $output;
101             }
102              
103 149     149   269 sub _render ($self, $method, @args) {
  149         304  
  149         214  
  149         207  
  149         241  
104 149         254 local $Template::Caribou::TEMPLATE = $self;
105            
106 149         280 local $Template::Caribou::IN_RENDER = 1;
107 149         701 local $Template::Caribou::OUTPUT;
108              
109 149 50       345 unless(ref $method) {
110 0 0       0 $method = $self->can($method)
111             or die "no template named '$method' found\n";
112             }
113              
114 149         475 local *STDOUT;
115 149         316 local *::RAW;
116 149         1922 tie *STDOUT, 'Template::Caribou::Output';
117 149         787 tie *::RAW, 'Template::Caribou::OutputRaw';
118              
119 149         458 select STDOUT;
120              
121 149         1207 my $res = $method->( $self, @args );
122              
123 149   66     1272 return( $Template::Caribou::OUTPUT
124             or ref $res ? $res : Template::Caribou::Output::escape( $res ) );
125             }
126              
127             1;
128              
129             __END__
130              
131             =pod
132              
133             =encoding UTF-8
134              
135             =head1 NAME
136              
137             Template::Caribou::Role - Caribou core engine
138              
139             =head1 VERSION
140              
141             version 1.2.2
142              
143             =head1 SYNOPSIS
144              
145             package MyTemplate;
146              
147             use Template::Caribou;
148              
149             has name => ( is => 'ro' );
150              
151             template greetings => sub {
152             my $self = shift;
153              
154             print "hello there, ", $self->name;
155             };
156              
157             # later on...
158            
159             my $template = MyTemplate->new( name => 'Yanick' );
160              
161             print $template->greetings;
162              
163             =head1 DESCRIPTION
164              
165             This role implements the rendering core of Caribou, which mostly deals
166             with defining the templates of a class and calling them.
167              
168             =head2 The templates
169              
170             The templates are subs expected to print or return the content they are generating.
171             Under the hood, they are snugly wrapped within a C<render> call and turned
172             into methods of the template class.
173              
174             package MyTemplate;
175              
176             use Template::Caribou;
177              
178             has name => ( is => 'ro' );
179              
180             template greetings => sub {
181             my( $self, %args ) = @_;
182              
183             'hi there ' . $self->name . '!' x $args{excited};
184             };
185              
186             my $bou = MyTemplate->new( name => 'Yanick' );
187              
188             print $bou->greetings;
189             # prints 'hi there Yanick'
190              
191             print $bou->greetings(excited => 1);
192             # print 'hi there Yanick!
193              
194             In addition of those arguments, the file descriptions
195             C<::STDOUT> and C<::RAW> are locally defined. Anything printed to C<::RAW> is added verbatim to the
196             content of the template, whereas something printed to C<STDOUT> will be HTML-escaped.
197              
198             If nothing has been printed at all by the template, it'll take its return
199             value as its generated content.
200              
201             # prints '&lt;hey>'
202             print MyTemplate->render(sub{
203             print "<hey>";
204             });
205            
206             # prints '<hey>'
207             print MyTemplate->render(sub{
208             print ::RAW "<hey>";
209             });
210              
211             # prints 'onetwo'
212             print MyTemplate->render(sub{
213             print "one";
214             print "two";
215             });
216            
217             # prints 'one'
218             print MyTemplate->render(sub{
219             print "one";
220             return "ignored";
221             });
222            
223             # prints 'no print, not ignored'
224             print MyTemplate->render(sub{
225             return "no print, not ignored";
226             });
227              
228             Template methods can, of course, be called within other template methods.
229             When invoked from within a template, their content is implicitly printed
230             to C<::RAW>.
231              
232             template outer => sub {
233             my $self = shift;
234              
235             say 'alpha';
236             $self->inner;
237             say 'gamma';
238             };
239              
240             template inner => sub {
241             say 'beta';
242             };
243              
244             ...;
245              
246             print $bou->outer; # prints 'alpha beta gamma'
247              
248             =head2 Definiting templates via template instances
249              
250             Templates are usually defined for the class via the
251             C<template> keyword. C<template> can also be used as a method. By default,
252             though, it'll die as adding a template that way will not only add it to
253             the instance, but for to class itself, which is probably more
254             than you bargained for.
255              
256             $bou->template( foo => sub { ... } );
257             # dies with 'can only add templates from instances created
258             # via 'anon_instance' or with the attribute 'can_add_templates'
259              
260             If you want to add a template to a single instance, use
261             the class method C<anon_instance>, which will create a singleton
262             class inheriting from the main template class.
263              
264             my $bou = MyTemplate->anon_instance( name => 'Yanick' );
265              
266             $bou->template( foo => sub { ... } ); # will work
267              
268             Or if you really want to augment the whole class with new
269             templates, you can set the C<can_add_templates> attribute of
270             the object to C<true>.
271              
272             $bou->can_add_templates(1);
273             $bou->template( foo => sub { ... } ); # will work too
274              
275             =head1 METHODS
276              
277             =head2 new
278              
279             my $bou = MyTemplate->new(
280             indent => 1,
281             can_add_templates => 0,
282             );
283              
284             =over
285              
286             =item indent => $boolean
287              
288             If set to a C<true> value, the nested tags rendered inside
289             the templates will be indented. Defaults to C<true>.
290              
291             =item can_add_templates
292              
293             If templates can be added to the class via the method
294             invocation of C<template>.
295              
296             =back
297              
298             =head2 indent
299              
300             $bou->indent($bool);
301              
302             Accessor to the indent attribute. Indicates if the tags rendered
303             within the templates should be pretty-printed with indentation or not.
304              
305             =head2 can_add_templates
306              
307             $bou->can_add_templates($bool);
308              
309             Accessor. If set to C<true>, allows new templates to be
310             defined for the class via the C<template> method.
311              
312             =head2 template( $name => sub { ... } )
313              
314             Defines the template C<$name>. Will trigger an exception unless
315             C<can_add_templates> was set to C<true> or the object was
316             created via C<anon_instance>.
317              
318             Warnings will be issued if the template redefines an already-existing
319             function/method in the namespace.
320              
321             =head2 anon_instance(@args_for_new)
322              
323             Creates an anonymous class inheriting from the current one and builds an object instance
324             with the given arguments. Useful when wanting to define templates for one specific instance.
325              
326             =head2 render
327              
328             $bou->render( $coderef, @template_args );
329             $bou->render( $template_name, @template_args );
330              
331             Renders the given C<$coderef> as a template, passing it the C<@template_args>, and returns its generated output.
332              
333             print $bou->render( sub {
334             my( $self, $name ) = @_;
335              
336             'hi ' . $name . "\n";
337             }, $_ ) for @friends;
338              
339             The template can also be given by name.
340              
341             template foo => sub { ... };
342              
343             # later on
344              
345             $bou->render( 'foo', @args );
346              
347             # which is equivalent to
348              
349             $bou->foo(@args);
350              
351             =head2 get_render
352              
353             Like C<render>, but always return the generated template content, even
354             when called inside a template.
355              
356             template foo => sub { 'foo' };
357             template bar => sub { 'bar' };
358              
359             print $bou->render(sub{
360             my $self = shift;
361              
362             $self->foo;
363             my $bar = $self->get_render(sub{ $self->bar });
364             $bar =~ y/r/z/;
365             say $bar;
366             });
367              
368             # prints 'foobaz'
369              
370             =head1 SEE ALSO
371              
372             L<http://babyl.dyndns.org/techblog/entry/caribou> - The original blog entry
373             introducing L<Template::Caribou>.
374              
375             L<Template::Declare>
376              
377             =head1 AUTHOR
378              
379             Yanick Champoux <yanick@cpan.org>
380              
381             =head1 COPYRIGHT AND LICENSE
382              
383             This software is copyright (c) 2023 by Yanick Champoux.
384              
385             This is free software; you can redistribute it and/or modify it under
386             the same terms as the Perl 5 programming language system itself.
387              
388             =cut