File Coverage

blib/lib/Statocles/Page.pm
Criterion Covered Total %
statement 44 44 100.0
branch 10 10 100.0
condition 2 3 66.6
subroutine 12 12 100.0
pod 6 6 100.0
total 74 75 98.6


line stmt bran cond sub pod time code
1             package Statocles::Page;
2             our $VERSION = '0.084';
3             # ABSTRACT: Base role for rendering files
4              
5 59     59   84975 use Statocles::Base 'Role';
  59         142  
  59         549  
6 59     59   424332 use Statocles::Template;
  59         171  
  59         1862  
7 59     59   347 use Statocles::Util qw( uniq_by );
  59         127  
  59         3157  
8 59     59   320 use Statocles::Person;
  59         117  
  59         64491  
9              
10             #pod =attr site
11             #pod
12             #pod The site this page is part of.
13             #pod
14             #pod =cut
15              
16             has site => (
17             is => 'ro',
18             isa => InstanceOf['Statocles::Site'],
19             lazy => 1,
20             default => sub { $Statocles::SITE },
21             );
22              
23             #pod =attr app
24             #pod
25             #pod The application this page came from, so we can give it to the templates.
26             #pod
27             #pod =cut
28              
29             has app => (
30             is => 'ro',
31             isa => ConsumerOf['Statocles::App'],
32             );
33              
34             #pod =attr path
35             #pod
36             #pod The absolute URL path to save this page to.
37             #pod
38             #pod =cut
39              
40             has path => (
41             is => 'rw',
42             isa => Path,
43             coerce => Path->coercion,
44             required => 1,
45             );
46              
47             #pod =attr title
48             #pod
49             #pod The title of the page. Any unsafe characters in the title (C<E<lt>>,
50             #pod C<E<gt>>, C<">, and C<&>) will be escaped by the template, so no HTML
51             #pod allowed.
52             #pod
53             #pod =cut
54              
55             has title => (
56             is => 'rw',
57             isa => Str,
58             default => '',
59             );
60              
61             #pod =attr author
62             #pod
63             #pod The author of the page.
64             #pod
65             #pod =cut
66              
67             has author => (
68             is => 'rw',
69             isa => Person,
70             coerce => Person->coercion,
71             lazy => 1,
72             builder => '_build_author',
73             );
74              
75             sub _build_author {
76 91     91   21492 my ( $self ) = @_;
77 91   66     1421 return $self->site->author || Statocles::Person->new( name => '' );
78             }
79              
80             #pod =attr type
81             #pod
82             #pod The MIME type of this page. By default, will use the L<path's|/path> file extension
83             #pod to detect a likely type.
84             #pod
85             #pod =cut
86              
87             our %TYPES = (
88             # text
89             html => 'text/html',
90             markdown => 'text/markdown',
91             css => 'text/css',
92              
93             # image
94             jpg => 'image/jpeg',
95             jpeg => 'image/jpeg',
96             png => 'image/png',
97             gif => 'image/gif',
98              
99             # application
100             rss => 'application/rss+xml',
101             atom => 'application/atom+xml',
102             js => 'application/javascript',
103             json => 'application/json',
104             );
105              
106             has type => (
107             is => 'ro',
108             isa => Str,
109             lazy => 1,
110             default => sub {
111             my ( $self ) = @_;
112             my ( $ext ) = $self->path =~ /[.]([^.]+)$/;
113             return $TYPES{ $ext };
114             },
115             );
116              
117             #pod =attr date
118             #pod
119             #pod The date of this page. Used for last updated date and blog post dates.
120             #pod
121             #pod =cut
122              
123             has date => (
124             is => 'rw',
125             isa => DateTimeObj,
126             coerce => DateTimeObj->coercion,
127             lazy => 1,
128             default => sub { DateTime::Moonpig->now( time_zone => 'local' ) },
129             );
130              
131             #pod =attr data
132             #pod
133             #pod A hash of additional template variables for this page.
134             #pod
135             #pod =cut
136              
137             # XXX: For now this is the only way to add arbitrary template vars to
138             # the page. In the Statocles::Page::Document class, it defaults to the
139             # data attribute of the Document object. I suspect this might create
140             # a conflict when both the document and the application need to add
141             # arbitrary template variables. If that happens, we will require a new,
142             # application-only attribute.
143             has data => (
144             is => 'ro',
145             isa => HashRef,
146             default => sub { {} },
147             );
148              
149             #pod =attr links
150             #pod
151             #pod A hash of arrays of links to pages related to this page. Possible keys:
152             #pod
153             #pod feed - Feed pages related to this page
154             #pod alternate - Alternate versions of this page posted to other sites
155             #pod stylesheet - Additional stylesheets for this page
156             #pod script - Additional scripts for this page
157             #pod
158             #pod Each item in the array is a L<link object|Statocles::Link>. The most common
159             #pod attributes are:
160             #pod
161             #pod text - The text of the link
162             #pod href - The page for the link
163             #pod type - The MIME type of the link, optional
164             #pod
165             #pod =cut
166              
167             has _links => (
168             is => 'ro',
169             isa => LinkHash,
170             lazy => 1,
171             default => sub { +{} },
172             coerce => LinkHash->coercion,
173             init_arg => 'links',
174             );
175              
176             #pod =attr images
177             #pod
178             #pod A hash of images related to this page. Each value should be an L<image
179             #pod object|Statocles::Image>. These are used by themes to show images next
180             #pod to articles, thumbnails, and/or shortcut icons.
181             #pod
182             #pod =cut
183              
184             has _images => (
185             is => 'ro',
186             isa => HashRef[InstanceOf['Statocles::Image']],
187             lazy => 1,
188             default => sub { +{} },
189             init_arg => 'images',
190             );
191              
192             #pod =attr markdown
193             #pod
194             #pod The markdown object to render document Markdown. Defaults to L<the markdown
195             #pod attribute from the Site object|Statocles::Site/markdown>.
196             #pod
197             #pod Any object with a "markdown" method will work.
198             #pod
199             #pod =cut
200              
201             has markdown => (
202             is => 'rw',
203             isa => HasMethods['markdown'],
204             default => sub { $_[0]->site->markdown },
205             );
206              
207             #pod =attr template
208             #pod
209             #pod The main L<template|Statocles::Template> for this page. The result will be
210             #pod wrapped in the L<layout template|/layout>.
211             #pod
212             #pod =cut
213              
214             my @template_attrs = (
215             is => 'rw',
216             isa => InstanceOf['Statocles::Template'],
217             coerce => Statocles::Template->coercion,
218             default => sub {
219             Statocles::Template->new( content => '<%= content %>' ),
220             },
221             );
222              
223             has template => @template_attrs;
224              
225             #pod =attr layout
226             #pod
227             #pod The layout L<template|Statocles::Template> for this page, which will wrap the content generated by the
228             #pod L<template|/template>.
229             #pod
230             #pod =cut
231              
232             has layout => @template_attrs;
233              
234             #pod =attr search_change_frequency
235             #pod
236             #pod How frequently a search engine should check this page for changes. This is used
237             #pod in the L<sitemap.xml|http://www.sitemaps.org> to give hints to search engines.
238             #pod
239             #pod Should be one of:
240             #pod
241             #pod always
242             #pod hourly
243             #pod daily
244             #pod weekly
245             #pod monthly
246             #pod yearly
247             #pod never
248             #pod
249             #pod Defaults to C<weekly>.
250             #pod
251             #pod B<NOTE:> This is only a hint to search engines, not a command. Pages marked C<hourly>
252             #pod may be checked less often, and pages marked C<never> may still be checked once in a
253             #pod while. C<never> is mainly used for archived pages or permanent links.
254             #pod
255             #pod =cut
256              
257             has search_change_frequency => (
258             is => 'rw',
259             isa => Enum[qw( always hourly daily weekly monthly yearly never )],
260             default => sub { 'weekly' },
261             );
262              
263             #pod =attr search_priority
264             #pod
265             #pod How high should this page rank in search results compared to similar pages on
266             #pod this site? This is used in the L<sitemap.xml|http://www.sitemaps.org> to rank
267             #pod individual, full pages more highly than aggregate, list pages.
268             #pod
269             #pod Value should be between C<0.0> and C<1.0>. The default is C<0.5>.
270             #pod
271             #pod This is only used to decide which pages are more important for the search
272             #pod engine to crawl, and which pages within your site should be given to users. It
273             #pod does not improve your rankings compared to other sites. See L<the sitemap
274             #pod protocol|http://sitemaps.org> for details.
275             #pod
276             #pod =cut
277              
278             has search_priority => (
279             is => 'rw',
280             isa => Num,
281             default => sub { 0.5 },
282             );
283              
284             # _rendered_html
285             #
286             # The HTML rendered from the page. Cached.
287              
288             has _rendered_html => (
289             is => 'rw',
290             isa => Str,
291             predicate => '_has_rendered_html',
292             );
293              
294             # _content_sections
295             #
296             # The saved content sections from any rendered content templates. This
297             # is private for now. We might make this public later
298             has _content_sections => (
299             is => 'rw',
300             isa => HashRef,
301             default => sub { {} },
302             );
303              
304             #pod =method vars
305             #pod
306             #pod my %vars = $page->vars;
307             #pod
308             #pod Get extra template variables for this page
309             #pod
310             #pod =cut
311              
312             sub vars {
313 1542     1542 1 3196 my ( $self ) = @_;
314             return (
315 1542         23704 app => $self->app,
316             site => $self->site,
317             self => $self,
318             page => $self,
319             );
320             }
321              
322             #pod =method render
323             #pod
324             #pod my $html = $page->render( %vars );
325             #pod
326             #pod Render the page, using the L<template|Statocles::Page/template> and wrapping
327             #pod with the L<layout|Statocles::Page/layout>. Give any extra C<%vars> to the
328             #pod template, layout, and page C<content> method (if applicable).
329             #pod
330             #pod The result of this method is cached.
331             #pod
332             #pod =cut
333              
334             sub render {
335 1096     1096 1 389549 my ( $self, %args ) = @_;
336              
337 1096 100       5836 if ( $self->_has_rendered_html ) {
338 59         1054 $self->site->log->debug( 'Render page (cached): ' . $self->path );
339 59         5561 return $self->_rendered_html;
340             }
341              
342 1037         24440 $self->site->log->debug( 'Render page: ' . $self->path );
343              
344             my %vars = (
345 1037         80689 %{ $self->data },
  1037         21288  
346             %args,
347             $self->vars,
348             );
349              
350 1037 100       14707 my %tmpl_vars = (
351             # XXX: This is suboptimal. Isn't vars() enough?
352             ( $self->can( 'content' ) ? ( content => $self->content( %vars ) ) : () ),
353             %vars,
354             );
355              
356 1037         908438 my $content = $self->template->render( %tmpl_vars );
357              
358 1037         26906 my $html = $self->layout->render(
359             content => $content,
360             %vars,
361             );
362              
363 1037         23814 $self->_rendered_html( $html );
364 1037         41783 return $html;
365             }
366              
367             #pod =method links
368             #pod
369             #pod my @links = $page->links( $key );
370             #pod my $link = $page->links( $key );
371             #pod $page->links( $key => $add_link );
372             #pod
373             #pod Get or append to the links set for the given key. See L<the links
374             #pod attribute|/links> for some commonly-used keys.
375             #pod
376             #pod If only one argument is given, returns a list of L<link
377             #pod objects|Statocles::Link>. In scalar context, returns the first link in
378             #pod the list.
379             #pod
380             #pod If two or more arguments are given, append the new links to the given
381             #pod key. C<$add_link> may be a URL string, a hash reference of L<link
382             #pod attributes|Statocles::Link/ATTRIBUTES>, or a L<Statocles::Link
383             #pod object|Statocles::Link>. When adding links, nothing is returned.
384             #pod
385             #pod =cut
386              
387             sub links {
388 2436     2436 1 30447 my ( $self, $name, @add_links ) = @_;
389 2436 100       5826 if ( @add_links ) {
390 312         432 push @{ $self->_links->{ $name } }, map { Link->coerce( $_ ) } @add_links;
  312         4590  
  616         32811  
391 312         10102 return;
392             }
393 1759     1759   25936 my @links = uniq_by { $_->href }
394 2124 100       43901 $self->_links->{ $name } ? @{ $self->_links->{ $name } } : ();
  1509         40284  
395 2124 100       30814 return wantarray ? @links : $links[0];
396             }
397              
398             #pod =method images
399             #pod
400             #pod my $image = $page->images( $key );
401             #pod
402             #pod Get the images for the given key. See L<the images attribute|/images> for some
403             #pod commonly-used keys. Returns an L<image object|Statocles::Image>.
404             #pod
405             #pod =cut
406              
407             sub images {
408 1     1 1 1072 my ( $self, $name ) = @_;
409             # This exists here as a placeholder in case we ever need to handle
410             # arrays of images, which I anticipate will happen when we build
411             # image galleries or want to be able to pick a single random image
412             # from an array.
413 1         23 return $self->_images->{ $name };
414             }
415              
416             #pod =method basename
417             #pod
418             #pod my $name = $page->basename;
419             #pod
420             #pod Get the base file name of this page. Everything after the last C</>.
421             #pod
422             #pod =cut
423              
424             sub basename {
425 3     3 1 65 my ( $self ) = @_;
426 3         47 return $self->path->basename;
427             }
428              
429             #pod =method dirname
430             #pod
431             #pod my $dir = $page->dirname;
432             #pod
433             #pod Get the full directory to this page. Anything that isn't part of L</basename>.
434             #pod
435             #pod There will not be a trailing slash unless it is the root directory.
436             #pod
437             #pod =cut
438              
439             sub dirname {
440 3706     3706 1 6280 my ( $self ) = @_;
441 3706         60780 return $self->path->parent->stringify;
442             }
443              
444             1;
445              
446             __END__
447              
448             =pod
449              
450             =encoding UTF-8
451              
452             =head1 NAME
453              
454             Statocles::Page - Base role for rendering files
455              
456             =head1 VERSION
457              
458             version 0.084
459              
460             =head1 DESCRIPTION
461              
462             A Statocles::Page takes one or more L<documents|Statocles::Document> and
463             renders them into one or more HTML pages using a main L<template|/template>
464             and a L<layout template|/layout>.
465              
466             =head1 ATTRIBUTES
467              
468             =head2 site
469              
470             The site this page is part of.
471              
472             =head2 app
473              
474             The application this page came from, so we can give it to the templates.
475              
476             =head2 path
477              
478             The absolute URL path to save this page to.
479              
480             =head2 title
481              
482             The title of the page. Any unsafe characters in the title (C<E<lt>>,
483             C<E<gt>>, C<">, and C<&>) will be escaped by the template, so no HTML
484             allowed.
485              
486             =head2 author
487              
488             The author of the page.
489              
490             =head2 type
491              
492             The MIME type of this page. By default, will use the L<path's|/path> file extension
493             to detect a likely type.
494              
495             =head2 date
496              
497             The date of this page. Used for last updated date and blog post dates.
498              
499             =head2 data
500              
501             A hash of additional template variables for this page.
502              
503             =head2 links
504              
505             A hash of arrays of links to pages related to this page. Possible keys:
506              
507             feed - Feed pages related to this page
508             alternate - Alternate versions of this page posted to other sites
509             stylesheet - Additional stylesheets for this page
510             script - Additional scripts for this page
511              
512             Each item in the array is a L<link object|Statocles::Link>. The most common
513             attributes are:
514              
515             text - The text of the link
516             href - The page for the link
517             type - The MIME type of the link, optional
518              
519             =head2 images
520              
521             A hash of images related to this page. Each value should be an L<image
522             object|Statocles::Image>. These are used by themes to show images next
523             to articles, thumbnails, and/or shortcut icons.
524              
525             =head2 markdown
526              
527             The markdown object to render document Markdown. Defaults to L<the markdown
528             attribute from the Site object|Statocles::Site/markdown>.
529              
530             Any object with a "markdown" method will work.
531              
532             =head2 template
533              
534             The main L<template|Statocles::Template> for this page. The result will be
535             wrapped in the L<layout template|/layout>.
536              
537             =head2 layout
538              
539             The layout L<template|Statocles::Template> for this page, which will wrap the content generated by the
540             L<template|/template>.
541              
542             =head2 search_change_frequency
543              
544             How frequently a search engine should check this page for changes. This is used
545             in the L<sitemap.xml|http://www.sitemaps.org> to give hints to search engines.
546              
547             Should be one of:
548              
549             always
550             hourly
551             daily
552             weekly
553             monthly
554             yearly
555             never
556              
557             Defaults to C<weekly>.
558              
559             B<NOTE:> This is only a hint to search engines, not a command. Pages marked C<hourly>
560             may be checked less often, and pages marked C<never> may still be checked once in a
561             while. C<never> is mainly used for archived pages or permanent links.
562              
563             =head2 search_priority
564              
565             How high should this page rank in search results compared to similar pages on
566             this site? This is used in the L<sitemap.xml|http://www.sitemaps.org> to rank
567             individual, full pages more highly than aggregate, list pages.
568              
569             Value should be between C<0.0> and C<1.0>. The default is C<0.5>.
570              
571             This is only used to decide which pages are more important for the search
572             engine to crawl, and which pages within your site should be given to users. It
573             does not improve your rankings compared to other sites. See L<the sitemap
574             protocol|http://sitemaps.org> for details.
575              
576             =head1 METHODS
577              
578             =head2 vars
579              
580             my %vars = $page->vars;
581              
582             Get extra template variables for this page
583              
584             =head2 render
585              
586             my $html = $page->render( %vars );
587              
588             Render the page, using the L<template|Statocles::Page/template> and wrapping
589             with the L<layout|Statocles::Page/layout>. Give any extra C<%vars> to the
590             template, layout, and page C<content> method (if applicable).
591              
592             The result of this method is cached.
593              
594             =head2 links
595              
596             my @links = $page->links( $key );
597             my $link = $page->links( $key );
598             $page->links( $key => $add_link );
599              
600             Get or append to the links set for the given key. See L<the links
601             attribute|/links> for some commonly-used keys.
602              
603             If only one argument is given, returns a list of L<link
604             objects|Statocles::Link>. In scalar context, returns the first link in
605             the list.
606              
607             If two or more arguments are given, append the new links to the given
608             key. C<$add_link> may be a URL string, a hash reference of L<link
609             attributes|Statocles::Link/ATTRIBUTES>, or a L<Statocles::Link
610             object|Statocles::Link>. When adding links, nothing is returned.
611              
612             =head2 images
613              
614             my $image = $page->images( $key );
615              
616             Get the images for the given key. See L<the images attribute|/images> for some
617             commonly-used keys. Returns an L<image object|Statocles::Image>.
618              
619             =head2 basename
620              
621             my $name = $page->basename;
622              
623             Get the base file name of this page. Everything after the last C</>.
624              
625             =head2 dirname
626              
627             my $dir = $page->dirname;
628              
629             Get the full directory to this page. Anything that isn't part of L</basename>.
630              
631             There will not be a trailing slash unless it is the root directory.
632              
633             =head1 SEE ALSO
634              
635             =over
636              
637             =item L<Statocles::Page::Document>
638              
639             A page that renders a single document.
640              
641             =item L<Statocles::Page::List>
642              
643             A page that renders a list of other pages.
644              
645             =back
646              
647             =head1 AUTHOR
648              
649             Doug Bell <preaction@cpan.org>
650              
651             =head1 COPYRIGHT AND LICENSE
652              
653             This software is copyright (c) 2016 by Doug Bell.
654              
655             This is free software; you can redistribute it and/or modify it under
656             the same terms as the Perl 5 programming language system itself.
657              
658             =cut