File Coverage

blib/lib/Ado/Plugin/MarkdownRenderer.pm
Criterion Covered Total %
statement 42 43 97.6
branch 7 12 58.3
condition 20 27 74.0
subroutine 5 5 100.0
pod 2 2 100.0
total 76 89 85.3


line stmt bran cond sub pod time code
1             package Ado::Plugin::MarkdownRenderer;
2 23     23   25346 use Mojo::Base 'Ado::Plugin';
  23         46  
  23         163  
3             File::Basename->import('fileparse');
4             File::Spec::Functions->import(qw(catfile catdir));
5             Mojo::ByteStream->import('b');
6              
7             sub register {
8 24     24 1 8447 my ($self, $app, $config) = shift->initialise(@_);
9              
10             #Make sure we have all we need from config files.
11 24   100     123 $config->{md_renderer} ||= 'Text::MultiMarkdown';
12 24   100     99 $config->{md_method} ||= 'markdown';
13 24   100     84 $config->{md_options} ||= {use_wikilinks => 1,};
14 24   100     104 $config->{md_helper} ||= 'md_to_html';
15 24   66     92 $config->{md_root} ||= $app->home->rel_dir('public/doc');
16 24   33     218 $config->{md_articles_root} ||= $app->home->rel_dir('public/articles');
17 24   100     510 $config->{md_file_sufixes} ||= ['.md'];
18              
19 24 50       108 if ($config->{md_renderer} eq 'Text::MultiMarkdown') {
20 24         14437 require Text::MultiMarkdown;
21 24     50   521801 $app->helper($config->{md_helper} => sub { md_to_html(shift, $config, @_) });
  50         2560  
22             $app->helper(
23             markdown => sub {
24 29     29   2967 my $c = shift;
25 29         180 return Text::MultiMarkdown::markdown(@_);
26             }
27 24         936 );
28              
29             }
30              
31             #make plugin configuration available for later in the app
32 24         451 $app->config(__PACKAGE__, $config);
33 24         1508 return $self;
34             }
35              
36             sub md_to_html {
37 50     50 1 121 my ($c, $config, $file_path) = @_;
38 50   50     289 $file_path ||= ($c->stash('md_file') || return '');
      66        
39              
40             #remove anchors
41 50         582 $file_path =~ s{[^#]#.+}{};
42 50 0       160 unless ($file_path) { $c->reply->not_found() && return '' }
  0 50       0  
43 50         438 my $fullname = catfile($config->{md_root}, $file_path);
44 50         448 $c->debug("md_file: $file_path;\$fullname: $fullname");
45              
46 50         1160 my ($name, $path, $suffix) = fileparse($fullname, @{$config->{md_file_sufixes}});
  50         2434  
47 50         389 my $html_filepath = catfile($path, "$name.html");
48              
49             #Reuse previously produced html file if md_file is older than the html file.
50 50 100 66     3028 if ( $config->{md_reuse_produced_html}
      66        
51             && -s $html_filepath
52             && (stat($fullname))[9] < (stat($html_filepath))[9])
53             {
54 24         187 $c->debug('Found ' . $html_filepath);
55 24         535 return b($html_filepath)->slurp->decode;
56             }
57              
58             #404 Not Found
59 26         180 my $md_filepath = catfile($path, "$name$suffix");
60 26 50       697 unless (-s $md_filepath) { $c->reply->not_found() && return '' }
  1 100       13  
61              
62 25         120 my $markdown = Mojo::Util::slurp($md_filepath);
63 25         3376 my $self_url = $c->url_for()->to_string;
64 25         14727 my %options = (%{$config->{md_options}}, self_url => $self_url);
  25         204  
65 25         398 my $html = $c->markdown($markdown, \%options);
66 25         522383 $c->debug($c->dumper({'%options' => \%options, '$html_filepath' => $html_filepath}));
67 25         1222 return b($html)->spurt($html_filepath)->decode();
68             }
69              
70             1;
71              
72              
73             =pod
74              
75             =encoding utf8
76              
77             =head1 NAME
78              
79             Ado::Plugin::MarkDownRenderer - Render markdown to HTML
80              
81              
82             =head1 SYNOPSIS
83              
84             #1. Use one or more markup parsers
85             plugins => [
86             #...
87             #use default configuration
88             'markdown_renderer',
89              
90             #Create your own Text::Trac based wiki
91             {name => 'markdown_renderer', config => {
92             md_renderer =>'Text::Trac',
93             md_options => {
94             trac_url => '/wiki',
95             disable_links => [ qw( changeset ticket ) ],
96             },
97             md_method => 'parse',
98             md_helper =>'trac_to_html'
99             }},
100             #...
101             ],
102              
103             #2. Describe your routes
104             routes => [
105             #markdown_renderer route is already configured
106             #in etc/plugins/markdown_renderer.conf.
107              
108             #Your own great enterprise wiki
109             {route => '/wiki/*md_file', via => ['GET'],
110             to => 'wiki#show',},
111             #...
112             ],
113              
114             #3. Write your controller
115             package Ado::Control::Wiki;
116             use Mojo::Base 'Ado::Control';
117             #...
118              
119             =head1 DESCRIPTION
120              
121             L is a markdown renderer (маани, маани!)
122              
123             You only need to create a controller for your enterprise wiki and use
124             the L helper provided by this plugin.
125             See L for an example.
126              
127             You may use this plugin to load and use other markup languages parsers
128             and converters to HTML.
129              
130             The code of this plugin is a good example for learning to build new plugins,
131             you're welcome to fork it.
132              
133             =head1 OPTIONS
134              
135             The following options can be set in C
136             or C. You can find default options in
137             C. C prefix is short for "markup
138             document" or "markdown".
139              
140             =head2 md_renderer
141              
142             md_renderer => 'Text::MultiMarkdown',
143              
144             The class to load. This option exists because the user may want to use
145             L or L instead.
146              
147             =head2 md_method
148              
149             md_method => 'markdown',
150              
151             Method that will be used internally to produce the C<$HTML>.
152             Can also be a code reference.
153             First parameter is the md_renderer instance and the
154             second is the markdown text.
155              
156             =head2 md_options
157              
158             md_options => {
159             use_wikilinks => 1,
160             base_url => '/docs',
161             },
162              
163             These options will be passed to the md_renderer constructor.
164             They are specific for each markup parser so look at it's documentation.
165              
166             =head2 md_helper
167              
168             md_helper => 'md_to_html',
169              
170             Helper name. You may want to change this if you want to have
171             different helpers for different markup converters,
172             configurations, applications etc. in the same ado instance.
173             Default helper name is L.
174              
175             =head2 md_root
176              
177             md_root => app->home->rel_dir('public/doc'),
178              
179             Directory where the raw files reside.
180              
181             =head2 md_articles_root
182              
183             md_articles_root => app->home->rel_dir('public/articles'),
184              
185             Directory used by L where the raw markdown files reside
186             and where the static HTML files are generated.
187              
188              
189             =head2 md_file_sufixes
190              
191             md_file_sufixes => ['.md'],
192              
193             File-suffixes supported by your renderer.
194              
195             =head2 md_reuse_produced_html
196              
197             md_reuse_produced_html => 1,
198              
199             Do not convert files on every request but reuse already produced html files.
200              
201              
202             =head1 HELPERS
203              
204             L exports the following helpers for use in
205             L methods and templates.
206              
207             =head2 markdown
208              
209             Accepts markdown text and options. Returns HTML.
210             Accepts the same parameters as L
211              
212             #in a controller
213             $c->render(text=>$c->markdown($text));
214              
215             #in a template
216             %==markdown($text)
217              
218             =head2 md_to_html
219              
220             Given a Markdown string returns CarticleE$htmlE/articleE>
221             produced by the converter - L by default.
222             You may want to use your own helper name. See L.
223              
224             #Markdown from $MOJO_HOME/public/doc/bg/intro.md
225             #http://example.com/doc/bg/intro.md
226             my $html = $c->md_to_html();
227              
228             #Markdown from arbitrary file
229             my $html_string = $c->md_to_html($some_filepath);
230              
231             % #in a template
232             <%= md_to_html();%>
233             % #
$html
234              
235             =head1 METHODS
236              
237             L inherits all methods from
238             L and implements the following new ones.
239              
240             =head2 register
241              
242             my $plugin = $app->plugin('markdown_renderer' => $OPTIONS);
243              
244             Register renderer and helper in L. Return $self.
245              
246             =head1 SPONSORS
247              
248             The original author
249              
250             Become a sponsor and help make L the ERP for the enterprise!
251              
252             =head1 SEE ALSO
253              
254             L, L,
255             L, L,
256             L
257             L, L.
258              
259             =head1 AUTHOR
260              
261             Красимир Беров (Krasimir Berov)
262              
263             =head1 COPYRIGHT AND LICENSE
264              
265             Copyright 2013-2014 Красимир Беров (Krasimir Berov).
266              
267             This program is free software, you can redistribute it and/or
268             modify it under the terms of the
269             GNU Lesser General Public License v3 (LGPL-3.0).
270             You may copy, distribute and modify the software provided that
271             modifications are open source. However, software that includes
272             the license may release under a different license.
273              
274             See http://opensource.org/licenses/lgpl-3.0.html for more information.
275              
276             =cut