File Coverage

blib/lib/HiD/Role/IsConverted.pm
Criterion Covered Total %
statement 48 48 100.0
branch 2 2 100.0
condition n/a
subroutine 15 15 100.0
pod n/a
total 65 65 100.0


line stmt bran cond sub pod time code
1             # ABSTRACT: Role for objects that are converted during the publishing process
2              
3              
4             package HiD::Role::IsConverted;
5             our $AUTHORITY = 'cpan:GENEHACK';
6             $HiD::Role::IsConverted::VERSION = '1.99';
7 12     12   7703 use Moose::Role;
  12         4375  
  12         94  
8 12     12   58306 use namespace::autoclean;
  12         25  
  12         95  
9              
10 12     12   1014 use 5.014; # strict, unicode_strings
  12         44  
11 12     12   72 use utf8;
  12         28  
  12         86  
12 12     12   296 use autodie;
  12         26  
  12         78  
13 12     12   53427 use warnings qw/ FATAL utf8 /;
  12         24  
  12         538  
14 12     12   60 use open qw/ :std :utf8 /;
  12         20  
  12         82  
15 12     12   1602 use charnames qw/ :full /;
  12         30  
  12         76  
16              
17 12     12   2114 use Carp;
  12         21  
  12         935  
18 12     12   76 use Class::Load qw/ load_class /;
  12         25  
  12         503  
19 12     12   64 use Path::Tiny;
  12         25  
  12         468  
20 12     12   4521 use YAML::XS qw/ Load /; # YAML::Tiny doesn't support 'bool' types which we need 8^/
  12         23579  
  12         565  
21              
22 12     12   397 use HiD::Types;
  12         25  
  12         13781  
23              
24             requires 'get_default_layout';
25              
26              
27             has content => (
28             is => 'ro',
29             isa => 'Str',
30             required => 1 ,
31             );
32              
33              
34             has converted_content => (
35             is => 'ro' ,
36             isa => 'Str' ,
37             lazy => 1 ,
38             default => sub {
39             my $self = shift;
40              
41             my $content = $self->content;
42              
43             # process template directives in posts
44             if( $self->isa('HiD::Post' ) and $self->hid->has_processor() ) {
45             $self->hid->processor->process(
46             \$self->content , $self->template_data_without_content , \$content
47             );
48             }
49              
50             return _convert_by_extension( $content , $self->ext );
51             }
52             );
53              
54              
55             has converted_excerpt => (
56             is => 'ro' ,
57             isa => 'Str' ,
58             lazy => 1 ,
59             default => sub {
60             my $self = shift;
61              
62             my $converted_excerpt = _convert_by_extension( $self->excerpt , $self->ext );
63              
64             if ( $self->excerpt ne $self->content ) {
65             # Add the "read more" link
66             ### FIXME this should be configurable
67             $converted_excerpt .= $self->readmore_link;
68             }
69              
70             return $converted_excerpt;
71             },
72             );
73              
74              
75             has hid => (
76             is => 'ro' ,
77             isa => 'HiD' ,
78             required => 1 ,
79             handles => [ qw/ get_config /] ,
80             );
81              
82              
83             has layouts => (
84             is => 'ro' ,
85             isa => 'HashRef[HiD::Layout]' ,
86             required => 1 ,
87             );
88              
89              
90             has metadata => (
91             is => 'ro' ,
92             isa => 'HashRef' ,
93             default => sub {{}} ,
94             lazy => 1,
95             traits => [ 'Hash' ] ,
96             handles => {
97             get_metadata => 'get',
98             },
99             );
100              
101              
102             has readmore_link => (
103             is => 'ro' ,
104             isa => 'Str' ,
105             lazy => 1 ,
106             default => sub {
107             my $self = shift;
108              
109             if ( defined $self->get_config('readmore_link')) {
110             my $link = $self->get_config('readmore_link');
111             my $url = $self->url;
112             $link =~ s/__URL__/$url/;
113             return $link;
114             };
115              
116             return
117             q{<p class="readmore"><a href="}
118             . $self->url
119             . q{" class="readmore">read more</a></p>};
120             },
121             );
122              
123              
124             has rendered_content => (
125             is => 'ro' ,
126             isa => 'Str' ,
127             lazy => 1 ,
128             default => sub {
129             my $self = shift;
130              
131             my $layout_name = $self->get_metadata( 'layout' ) // $self->get_default_layout;
132              
133             my $layout = $self->layouts->{$layout_name} // $self->layouts->{default} //
134             die "FIXME no default layout?";
135              
136             my $output = $layout->render( $self->template_data );
137              
138             return $output;
139             }
140             );
141              
142              
143             has template_data => (
144             is => 'ro' ,
145             isa => 'HashRef' ,
146             lazy => 1 ,
147             default => sub {
148             my $self = shift;
149              
150             my $data = $self->template_data_without_content;
151              
152             $data->{content} = $self->converted_content;
153              
154             return $data;
155             },
156             );
157              
158              
159             has template_data_without_content => (
160             is => 'ro' ,
161             isa => 'HashRef' ,
162             lazy => 1 ,
163             default => sub {
164             my $self = shift;
165              
166             my $data = {
167             baseurl => $self->hid->config->{baseurl} ,
168             page => $self->metadata ,
169             site => $self->hid ,
170             timestamp => DateTime->now(),
171             };
172             $data->{post} = $self if $self->does('HiD::Role::IsPost');
173              
174             $data->{page}{url} = $self->url if $self->can( 'url' );
175              
176             return $data;
177             },
178             );
179              
180             around BUILDARGS => sub {
181             my $orig = shift;
182             my $class = shift;
183              
184             my %args = ( ref $_[0] and ref $_[0] eq 'HASH' ) ? %{ $_[0] } : @_;
185              
186             unless ( $args{content} and $args{metadata} ) {
187             my $file_content = path( $args{input_filename} )->slurp_utf8;
188              
189             my( $metadata , $content );
190             if ( $file_content =~ /^---/ ) {
191             ( $metadata , $content ) = $file_content
192             =~ /^---\n?(.*?)---\n?(.*)$/ms;
193             }
194             elsif ( $args{input_filename} =~ /\.html?$/ ) {
195             die "plain HTML file without YAML front matter"
196             }
197             else {
198             $content = $file_content;
199             $metadata = '';
200             }
201              
202             $args{content} = $content;
203             $args{metadata} = Load( $metadata ) // {};
204             }
205              
206             return $class->$orig( \%args );
207             };
208              
209             { # hide the map
210              
211             ### FIXME make this extensible
212             my %conversion_extension_map = (
213             markdown => [ 'Text::Markdown' , 'markdown' ] ,
214             mkdn => [ 'Text::Markdown' , 'markdown' ] ,
215             mk => [ 'Text::Markdown' , 'markdown' ] ,
216             md => [ 'Text::Markdown' , 'markdown' ] ,
217             mmd => [ 'Text::MultiMarkdown' , 'markdown' ] ,
218             textile => [ 'Text::Textile' , 'process' ] ,
219             );
220              
221             sub _convert_by_extension {
222 103     103   393 my( $content , $extension ) = @_;
223              
224             return $content
225 103 100       875 unless exists $conversion_extension_map{ $extension };
226              
227 84         168 my( $module , $method ) = @{ $conversion_extension_map{ $extension }};
  84         322  
228 84         589 load_class( $module );
229              
230 84         164298 my $converted = $module->new->$method( $content );
231 84         136250 return $converted;
232             }
233             }
234              
235 12     12   92 no Moose::Role;
  12         25  
  12         105  
236             1;
237              
238             __END__
239              
240             =pod
241              
242             =encoding UTF-8
243              
244             =head1 NAME
245              
246             HiD::Role::IsConverted - Role for objects that are converted during the publishing process
247              
248             =head1 SYNOPSIS
249              
250             package HiD::ThingThatIsConverted
251             use Moose;
252             with 'HiD::Role::IsConverted';
253              
254             ...
255              
256             1;
257              
258             =head1 DESCRIPTION
259              
260             This role is consumed by objects that are converted during the publication
261             process -- e.g., from Markdown or Textile to HTML, or rendered through a
262             layout object. This role provides required attributes and methods used during
263             that process.
264              
265             =head1 ATTRIBUTES
266              
267             =head2 content ( ro / Str / required )
268              
269             Page content (stuff after the YAML front matter)
270              
271             =head2 converted_content ( ro / Str / lazily built from content )
272              
273             Content after it has gone through the conversion process.
274              
275             Post objects will be rendered via the processor prior to conversion.
276              
277             =head2 converted_excerpt ( ro / Str / lazily built from content )
278              
279             Excerpt after it has gone through the conversion process
280              
281             =head2 hid
282              
283             The HiD object for the current site. Here primarily to provide access to site
284             metadata.
285              
286             =head2 layouts ( ro / HashRef[HiD::Layout] / required )
287              
288             Hashref of layout objects keyed by name.
289              
290             =head2 metadata ( ro / HashRef )
291              
292             Hashref of info from YAML front matter
293              
294             =head2 readmore_link
295              
296             Placed at the bottom of rendered excerpts. Intended to link to the full
297             version of the content.
298              
299             A string matching C<__URL__> will be replaced with the URL of the object (i.e.,
300             the output of C<$self->url>) being converted.
301              
302             =head2 rendered_content
303              
304             Content after any layouts have been applied
305              
306             =head2 template_data
307              
308             Data for passing to template processing function.
309              
310             =head2 template_data_without_content
311              
312             Data for passing to template processing function when processing things that will _be_ content (e.g., blog posts).
313              
314             =head1 VERSION
315              
316             version 1.99
317              
318             =head1 AUTHOR
319              
320             John SJ Anderson <genehack@genehack.org>
321              
322             =head1 COPYRIGHT AND LICENSE
323              
324             This software is copyright (c) 2015 by John SJ Anderson.
325              
326             This is free software; you can redistribute it and/or modify it under
327             the same terms as the Perl 5 programming language system itself.
328              
329             =cut