|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Dancer2::Plugin::MarkdownFilesToHTML ;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $Dancer2::Plugin::MarkdownFilesToHTML::VERSION = '0.017';  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: Easy conversion of markdown documents to HTML for display in your Dancer2 website  | 
| 
4
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1188394
 | 
 use 5.010; use strict; use warnings;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
15
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
9
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
13
 | 
 use Carp;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
146
 | 
    | 
| 
7
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
549
 | 
 use Encode                qw( decode );  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10305
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
113
 | 
    | 
| 
8
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
594
 | 
 use Storable;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3187
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
164
 | 
    | 
| 
9
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
22
 | 
 use File::Path            qw(make_path);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
132
 | 
    | 
| 
10
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
604
 | 
 use Data::Dumper          'Dumper';  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6137
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
    | 
| 
11
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
14
 | 
 use File::Basename;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
165
 | 
    | 
| 
12
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1050
 | 
 use Dancer2::Plugin;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
245011
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
13
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
47364
 | 
 use HTML::TreeBuilder;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63879
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
14
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
695
 | 
 use File::Spec::Functions qw(catfile);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
878
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
173
 | 
    | 
| 
15
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1127
 | 
 use Text::Markdown::Hoedown;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2635
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3825
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 plugin_keywords qw( md2html );  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has options             => (is => 'rw', default => sub { {} });  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has cache               => (is => 'ro', from_config => 'defaults.cache',               default => sub { 1 } );  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has prefix              => (is => 'ro', from_config => 'defaults.prefix',          default => sub { '' } );  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has layout              => (is => 'ro', from_config => 'defaults.layout',              default => sub { 'main.tt' } );  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has template            => (is => 'ro', from_config => 'defaults.template',            default => sub { 'index.tt' } );  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has file_root           => (is => 'ro', from_config => 'defaults.file_root',           default => sub { 'lib/data/markdown_files' } );  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has header_class        => (is => 'ro', from_config => 'defaults.header_class',        default => sub { '' } );  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has generate_toc        => (is => 'ro', from_config => 'defaults.generate_toc',        default => sub { 0  } );  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has exclude_files       => (is => 'ro', from_config => 'defaults.exclude_files',       default => sub { [] } );  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has include_files       => (is => 'ro', from_config => 'defaults.include_files',       default => sub { [] } );  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has linkable_headers    => (is => 'ro', from_config => 'defaults.linkable_headers',    default => sub { 0  } );  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has markdown_extensions => (is => 'ro', from_config => 'defaults.markdown_extensions', default => sub { [] } );  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Builds the routes from the config file  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub BUILD {  | 
| 
34
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
95
 | 
   my $s = shift;  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # add routes from config file  | 
| 
37
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
   foreach my $route (@{$s->config->{routes}}) {  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # validate arguments supplied from config file  | 
| 
40
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13308
 | 
     if ((ref $route) ne 'HASH') {  | 
| 
41
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       die 'Config file misconfigured. Check syntax or consult documentation.';  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
44
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     $s->_set_options($route);  | 
| 
45
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my %options = %{$s->options};  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $s->app->add_route(  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       method => 'get',  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       regexp => '/' . $options{prefix} . $options{path},  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       code => sub {  | 
| 
50
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
396762
 | 
         my ($html, $toc) = $s->md2html($options{resource}, \%options);  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $s->app->template($options{template},  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       { html => $html, toc => $toc },  | 
| 
53
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
                       { layout => $options{layout} });  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       },  | 
| 
55
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     );  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _set_options {  | 
| 
60
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
 
 | 
22
 | 
   my ($s, $options) = @_;  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
47
 | 
   my @settings = qw( cache layout template file_root prefix header_class  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     generate_toc exclude_files include_files linkable_headers markdown_extensions );  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
65
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
   my ($path)        = keys %$options;  | 
| 
66
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
158
 | 
   my $defaults      = $s->config->{defaults};  | 
| 
67
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
100
 | 
   my $local_options = (ref $options->{$path}) ? $options->{$path} : $options;  | 
| 
68
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
   my %options       = (%$defaults, %$local_options);  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
   foreach my $setting (@settings) {  | 
| 
71
 | 
88
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
1483
 | 
     $options{$setting} = $options{$setting} // $s->$setting;  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
74
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
   $options{set}               = 1;  | 
| 
75
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
   $options{path}              = $path;  | 
| 
76
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
   $options{prefix}           .= '/' if  $options{prefix};  | 
| 
77
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
22
 | 
   $options{linkable_headers}  = 1   if  $options{generate_toc};  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
79
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
87
 | 
   if (!File::Spec->file_name_is_absolute($options{resource})) {  | 
| 
80
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
     $options{resource} = File::Spec->catfile($options{file_root}, $options{resource});  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
82
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
   $s->options(\%options);  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Keyword for generating HTML  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub md2html {  | 
| 
87
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
  
1
  
 | 
73887
 | 
   my ($s, $resource, $options) = @_;  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # If keyword called directly, options won't be set yet  | 
| 
90
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   if (!$options->{set}) {  | 
| 
91
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     $options->{resource} = $resource;  | 
| 
92
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     $s->_set_options($options);  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } else {  | 
| 
94
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     $s->options($options);  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #TODO: return a 202 status code  | 
| 
98
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
311
 | 
   if (!-e $s->options->{resource}) {  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $html = 'This route is not properly configured. Resource: '  | 
| 
100
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
                   . $s->options->{resource} . ' does not exist on the server.';  | 
| 
101
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return ($html, undef);  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
   my @files = $s->_gather_files;  | 
| 
105
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
   my ($html, $toc) = '';  | 
| 
106
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
   foreach my $file (sort @files) {  | 
| 
107
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
293
 | 
     my ($file_html, $file_toc)  = $s->_mdfile_2html($file);  | 
| 
108
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
842
 | 
     $html                      .= $file_html;  | 
| 
109
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
392
 | 
     $toc                       .= $file_toc;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
111
 | 
7
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
399
 | 
   return wantarray ? ($html, $toc) : $html;  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _gather_files {  | 
| 
115
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
16
 | 
   my $s = shift;  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
117
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   my @files;  | 
| 
118
 | 
7
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
100
 | 
   if (-f $s->options->{resource}) {  | 
| 
119
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     push @files, $s->options->{resource};  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } else {  | 
| 
121
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
     my $dir = $s->options->{resource};  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # gather the files according the options supplied  | 
| 
123
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     if (@{$s->options->{include_files}}) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
124
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       my @files = @{$s->options->{include_files}};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
126
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
165
 | 
       opendir my $d, $dir or die "Cannot open directory: $!";  | 
| 
127
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
164
 | 
       @files = grep { $_ !~ /^\./ } readdir $d;  | 
| 
 
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
    | 
| 
128
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
       closedir $d;  | 
| 
129
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
       my @matching_files = ();  | 
| 
130
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
       foreach my $md_ext (@{$s->options->{markdown_extensions}}) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
131
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push @matching_files, grep { $_ =~ /\.$md_ext$/ } @files;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
133
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
       @files = @matching_files if @matching_files;  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
136
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     foreach my $excluded_file (@{$s->options->{exclude_files}}) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
137
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       @files = grep { $_ ne $excluded_file } @files;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     @files = map { File::Spec->catfile($dir, $_) } @files;  | 
| 
 
 | 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
331
 | 
    | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
142
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   return @files;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Sends the markdown file to get parsed or retrieves html version from cache,  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # if available. Also generates the table of contents.  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _mdfile_2html {  | 
| 
148
 | 
67
 | 
 
 | 
 
 | 
  
67
  
 | 
 
 | 
150
 | 
   my $s = shift;  | 
| 
149
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
173
 | 
   my $file = shift;  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # chop off extension  | 
| 
152
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4446
 | 
   my ($base)   = fileparse($file, qr/\.[^.]*/);  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # generate the cache directory if it doesn't exist  | 
| 
155
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6152
 | 
   my $cache_dir = File::Spec->catfile(dirname($s->options->{'file_root'}), 'md_file_cache');  | 
| 
156
 | 
67
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1406
 | 
   if (!-d $cache_dir) {  | 
| 
157
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
640
 | 
     make_path $cache_dir or die "Cannot make cache directory $!";  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # generate unique cache file name appended with options  | 
| 
161
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2516
 | 
   my $cache_file = dirname($file);  | 
| 
162
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
656
 | 
   my $sep = File::Spec->catfile('', '');  | 
| 
163
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4753
 | 
   $cache_file =~ s/\Q$sep\E//g;  | 
| 
164
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
627
 | 
   my $header_classes = $s->options->{header_class};  | 
| 
165
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
169
 | 
   $header_classes =~ s/ //g;  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $cache_file = File::Spec->catfile($cache_dir,  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     $cache_file  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     . $base  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     . $s->options->{linkable_headers}  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     . $s->options->{generate_toc}  | 
| 
171
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
811
 | 
                                     . $header_classes);  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # check for cache hit  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # TODO: Save options in separate file so they can be compared  | 
| 
175
 | 
67
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
6320
 | 
   if (-f $cache_file && $s->options->{cache}) {  | 
| 
176
 | 
17
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
391
 | 
     if (-M $cache_file eq -M $file) {  | 
| 
177
 | 
17
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
133
 | 
       print Dumper 'cache hit: '. $file if $ENV{DANCER_ENVIRONMENT} && $ENV{DANCER_ENVIRONMENT} eq 'testing';  | 
| 
178
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1065
 | 
       my $data = retrieve $cache_file;  | 
| 
179
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1384
 | 
       return ($data->{html}, $data->{toc});  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # no cache hit so we parse the file  | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # slurp the file and parse it with Hoedown's markdown function  | 
| 
185
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
175
 | 
   my $markdown = '';  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
187
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
166
 | 
     local $/;  | 
| 
 
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
413
 | 
    | 
| 
188
 | 
50
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
2566
 | 
     open my $md, '<:encoding(UTF-8)', $file or die "Can't open $file: $!";  | 
| 
189
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7382
 | 
     $markdown = <$md>;  | 
| 
190
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8694
 | 
     close $md;  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
192
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
361
 | 
   my $out  = markdown($markdown, extensions => HOEDOWN_EXT_FENCED_CODE, toc_nesting_lvl => 0);  | 
| 
193
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8142
 | 
   my $tree = HTML::TreeBuilder->new_from_content($out);  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
195
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1707173
 | 
   my @code_els = $tree->find_by_tag_name('code');  | 
| 
196
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38380
 | 
   foreach my $code_el (@code_els) {  | 
| 
197
 | 
2711
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
43716
 | 
     if (!$code_el->left && !$code_el->right) {  | 
| 
198
 | 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4769
 | 
       $code_el->attr('class' => 'single-line');  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # See if we can cache and return the output without further processing  | 
| 
203
 | 
50
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
1333
 | 
   if (!$s->options->{linkable_headers} && !$s->options->{header_class}) {  | 
| 
204
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
     my $html = $tree->guts->as_HTML;  | 
| 
205
 | 
17
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
285723
 | 
     _cache_data($cache_file, $file, $html) if $s->options->{cache};  | 
| 
206
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1994
 | 
     return ($html, '');  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # add linkable_headers, toc, and header_class per options  | 
| 
210
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
438
 | 
   my @elements = $tree->look_down(_tag => qr/^h\d$/);  | 
| 
211
 | 
33
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
30032
 | 
   my $toc      = HTML::TreeBuilder->new() if $s->options->{generate_toc};  | 
| 
212
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4193
 | 
   my $hdr_ct   = 0;  | 
| 
213
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
   foreach my $element (@elements) {  | 
| 
214
 | 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2979
 | 
     my $id = 'header_' . ${hdr_ct};  | 
| 
215
 | 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
369
 | 
     $hdr_ct++;  | 
| 
216
 | 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
762
 | 
     $element->attr('id', $id . '_' . $base);  | 
| 
217
 | 
246
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3065
 | 
     $element->attr('class' => $s->options->{header_class}) if $s->options->{header_class};  | 
| 
218
 | 
246
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1523
 | 
     if ($s->options->{generate_toc}) {  | 
| 
219
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
219
 | 
       my ($level) = $element->tag =~ /(\d)/;  | 
| 
220
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1053
 | 
       my $toc_link = HTML::Element->new('a', href=> "#${id}_${base}", class => 'header_' . $level);  | 
| 
221
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3282
 | 
       $toc_link->push_content($element->as_text);  | 
| 
222
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3948
 | 
       $toc->push_content($toc_link);  | 
| 
223
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1462
 | 
       $toc->push_content(HTML::Element->new('br'));  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Generate the final HTML from trees and cache  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # "guts" method gets rid of  and  tags added by TreeBuilder  | 
| 
229
 | 
33
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
564
 | 
   my ($html, $toc_out) = ($tree->guts->as_HTML, $toc ? $toc->guts->as_HTML : '');  | 
| 
230
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
454374
 | 
   _cache_data($cache_file, $file, $html, $toc_out);  | 
| 
231
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2404
 | 
   return ($html, $toc_out);  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _cache_data {  | 
| 
235
 | 
50
 | 
 
 | 
 
 | 
  
50
  
 | 
 
 | 
225
 | 
   my ($cache_file, $file, $content, $toc) = @_;  | 
| 
236
 | 
50
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
253
 | 
   $toc //= '';  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
238
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
508
 | 
   store { html => $content, toc => $toc }, $cache_file;  | 
| 
239
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18986
 | 
   my ($read, $write) = (stat($file))[8,9];  | 
| 
240
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1095
 | 
   utime($read, $write, $cache_file);  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |