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.991'; |
7
|
12
|
|
|
12
|
|
7176
|
use Moose::Role; |
|
12
|
|
|
|
|
3945
|
|
|
12
|
|
|
|
|
94
|
|
8
|
12
|
|
|
12
|
|
56945
|
use namespace::autoclean; |
|
12
|
|
|
|
|
27
|
|
|
12
|
|
|
|
|
88
|
|
9
|
|
|
|
|
|
|
|
10
|
12
|
|
|
12
|
|
979
|
use 5.014; # strict, unicode_strings |
|
12
|
|
|
|
|
36
|
|
11
|
12
|
|
|
12
|
|
68
|
use utf8; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
69
|
|
12
|
12
|
|
|
12
|
|
276
|
use autodie; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
68
|
|
13
|
12
|
|
|
12
|
|
52760
|
use warnings qw/ FATAL utf8 /; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
491
|
|
14
|
12
|
|
|
12
|
|
63
|
use open qw/ :std :utf8 /; |
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
67
|
|
15
|
12
|
|
|
12
|
|
1544
|
use charnames qw/ :full /; |
|
12
|
|
|
|
|
29
|
|
|
12
|
|
|
|
|
67
|
|
16
|
|
|
|
|
|
|
|
17
|
12
|
|
|
12
|
|
2107
|
use Carp; |
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
816
|
|
18
|
12
|
|
|
12
|
|
69
|
use Class::Load qw/ load_class /; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
453
|
|
19
|
12
|
|
|
12
|
|
61
|
use Path::Tiny; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
450
|
|
20
|
12
|
|
|
12
|
|
4116
|
use YAML::XS qw/ Load /; # YAML::Tiny doesn't support 'bool' types which we need 8^/ |
|
12
|
|
|
|
|
23552
|
|
|
12
|
|
|
|
|
560
|
|
21
|
|
|
|
|
|
|
|
22
|
12
|
|
|
12
|
|
328
|
use HiD::Types; |
|
12
|
|
|
|
|
27
|
|
|
12
|
|
|
|
|
13214
|
|
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
|
|
275
|
my( $content , $extension ) = @_; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
return $content |
225
|
103
|
100
|
|
|
|
673
|
unless exists $conversion_extension_map{ $extension }; |
226
|
|
|
|
|
|
|
|
227
|
84
|
|
|
|
|
153
|
my( $module , $method ) = @{ $conversion_extension_map{ $extension }}; |
|
84
|
|
|
|
|
248
|
|
228
|
84
|
|
|
|
|
407
|
load_class( $module ); |
229
|
|
|
|
|
|
|
|
230
|
84
|
|
|
|
|
152748
|
my $converted = $module->new->$method( $content ); |
231
|
84
|
|
|
|
|
112538
|
return $converted; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
12
|
|
|
12
|
|
87
|
no Moose::Role; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
100
|
|
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.991 |
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 |