File Coverage

blib/lib/Statocles/Page.pm
Criterion Covered Total %
statement 44 44 100.0
branch 8 8 100.0
condition 2 3 66.6
subroutine 14 14 100.0
pod 7 7 100.0
total 75 76 98.6


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