File Coverage

blib/lib/DDG/Publisher/Site/Duckduckhack/Root.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package DDG::Publisher::Site::Duckduckhack::Root;
2             $DDG::Publisher::Site::Duckduckhack::Root::VERSION = '1044';
3 1     1   1803 use MooX;
  1         2  
  1         9  
4              
5 1     1   833 use IO::All;
  1         3  
  1         10  
6 1     1   662 use Data::Dumper;
  1         5544  
  1         60  
7 1     1   473 use DDP;
  1         28542  
  1         11  
8              
9 1     1   63 use File::Path qw(make_path);
  1         2  
  1         56  
10 1     1   6 use File::Find;
  1         1  
  1         60  
11 1     1   326 use File::chdir;
  0            
  0            
12              
13             use Path::Class;
14              
15             use Markdent::Handler::HTMLStream::Document;
16             use Markdent::Parser;
17              
18             use Text::Trim;
19              
20             use JSON;
21              
22             use IPC::Run qw{run timeout};
23              
24             with qw(
25             DDG::Publisher::DirRole
26             );
27              
28             has nav_file => (
29             is => 'ro',
30             lazy => 1,
31             builder => sub {'ddh-index.md'},
32             );
33              
34             has prev_next_file => (
35             is => 'ro',
36             lazy => 1,
37             builder => sub {'ddh-prev-next.json'},
38             );
39              
40             has source_dir => (
41             is => 'ro',
42             lazy => 1,
43             builder => 1,
44             );
45              
46             sub _build_source_dir {
47             my ( $self ) = @_;
48              
49             my $cache_dir = $self->site->publisher->cache_dir;
50              
51             my $source_dir = dir($cache_dir,'duckduckgo-documentation/duckduckhack');
52              
53             {
54             my ($in, $out, $err);
55              
56             # die $cache_dir;
57             if (-d $source_dir) {
58             local $CWD = $source_dir;
59             run [
60             'git', 'pull'
61             ], \$in, \$out, \$err, timeout(60) or die "$err (error $?) $out";
62             } else {
63             local $CWD = $cache_dir;
64             run [
65             'git', 'clone', 'git@github.com:duckduckgo/duckduckgo-documentation.git'
66             ], \$in, \$out, \$err, timeout(60) or die "$err (error $?) $out";
67             }
68             }
69              
70             # warn qq(DUCKDUCKHACK source_dir: $source_dir\n);
71             # die;
72              
73             return $source_dir;
74             }
75              
76             sub path { '/' }
77              
78             # Builds the prev/next hash to push to each template.
79             sub get_prev_next {
80             my $self = shift;
81              
82             my $prev_next_path = dir($self->source_dir,$self->prev_next_file);
83             my $json = io($prev_next_path)->slurp;
84             $json =~ s/\.md//g;
85             my $data = decode_json $json;
86              
87             # die p($data);
88              
89             return $data;
90             }
91              
92             # Builds the nav hash to push to each template.
93             sub get_nav {
94             my $self = shift;
95              
96             my $nav_path = dir($self->source_dir,$self->nav_file);
97             my $markdown = io($nav_path)->slurp;
98              
99             # die $markdown;
100              
101             my %nav = ();
102             my @nav = ();
103             HEADING: foreach my $heading (split(/\n\-/s,$markdown)) {
104             next HEADING if !$heading;
105             next HEADING if $heading !~ /\*\*/;
106              
107             my $title = '';
108             my @sec = ();
109             LINE: foreach my $line (split(/\n/,$heading)) {
110             if ($line =~ /\*\*([^\*]+)/) {
111             $title = $1;
112              
113             # Capturing markdown link.
114             } elsif ($line =~ /\[([^\]]+)\]\(([^\)]+)/) {
115             my $section = $1;
116             my $link = $2;
117             $link =~ s/^.*\/(.*)\.md/$1/;
118             my %sec = ();
119             $sec{'title'} = $section;
120             $sec{'link'} = $link;
121             push(@sec,\%sec);
122            
123             $nav{$link} = {
124             'category' => $title,
125             'title' => $section,
126             }
127             }
128             }
129              
130             if ($title) {
131             my %sec = ();
132             $sec{'title'} = $title;
133             $sec{'sections'} = \@sec;
134             push(@nav,\%sec);
135             }
136             }
137              
138             # die p(%nav);
139             return \@nav, \%nav;
140             }
141              
142             # For just testing output.
143             my $dir_output = '/usr/local/ddg/www-static/duckduckhack.com/tmp';
144              
145             sub pages {
146             my $self = shift;
147              
148             my %pages = ();
149              
150             # Old index.
151             $pages{'index'} = sub {};
152              
153             my $prev_next_hash_ref = $self->get_prev_next;
154             my %prev_next = %{$prev_next_hash_ref};
155              
156             my ($nav_arr_ref,$nav_hash_ref) = $self->get_nav;
157             my %nav = %{$nav_hash_ref};
158              
159             find(sub {
160              
161             my $name = $File::Find::name;
162             my $dir = $File::Find::dir;
163              
164             return if $name =~ /$self->{nav_file}/;
165              
166             return unless $name =~ /^[^.].+\.md$/; # only markdown files
167             # warn qq($name\n);
168              
169             my ($file) = $name =~ /^$self->{source_dir}\/(.*)\.md/;
170             my $dir_rel = '';
171             ($dir_rel,$file) = $file =~ /^(.*)\/(.*)/ if $file =~ /\//;
172             # warn qq($dir_rel\t$file\n);;
173              
174             my $markdown = io($name)->slurp;
175              
176             # Replaces hard github links to other markdown files to our newly converted relative links
177             $markdown =~ s~(\]\()https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/(?:[^\/\.]+\/){1,4}([^\.]+?)\.md([^\)]*?\))~$1$2$3~sg;
178             # die $markdown;
179              
180             # Replace code types the parser can't deal with,
181             # that is a #### line without a space line between it and a code start line ```
182             $markdown =~ s/(\n\#+.*?)(\n`)/$1\n$2/sg;
183              
184             # die $markdown if $file eq 'spice_frontend_walkthroughs';
185              
186             # Just for debugging.
187             # make_path("$dir_output/$dir_rel") if $dir_rel;
188             # open(IN,">$dir_output/$dir_rel/$file.html");
189             my $buffer = q{};
190             open my $fh, '>', \$buffer;
191              
192             my $handler = Markdent::Handler::HTMLStream::Document->new(
193             title => $name,
194             output => $fh,
195             # output => \*IN,
196             );
197              
198             my $parser = Markdent::Parser->new( dialect => 'GitHub', handler => $handler );
199             $parser->parse( markdown => $markdown );
200              
201             my $html = $buffer;
202              
203             # Gets embedded in wrapped html.
204             $html =~ s/^.*?<html>.*?<\/head>\s*<body>\s*//s;
205             $html =~ s/\s*<\/body>.*?<\/html>\s*$//s;
206              
207             # Make anchors for headings.
208             $html =~ s/(<h\d>)(.*?)(<\/h\d>)/$1 . '<a name="' . make_anchor($2) . '" class="anchor"><\/a>' . $2 . $3/ges;
209              
210             # die $file;
211             # die $html if $file eq 'spice_frontend_walkthroughs';
212              
213              
214             my $category = $nav{$file}{'category'} || '';
215             my $title = $nav{$file}{'title'} || '';
216              
217             warn qq(NO CATEGORY: $file\n) if !$category;
218             # warn qq($file\t$title\t$category\n);
219              
220             my $prev = $prev_next{$file}{'prev'} || [];
221             my $next = $prev_next{$file}{'next'} || [];
222              
223             warn qq(NO PREV: $file\n) if !$prev;
224             warn qq(NO NEXT: $file\n) if !$next;
225              
226             # warn qq($file\t), p($prev);
227             # warn qq($file\t), p($next);
228              
229             $pages{$file} = sub {
230             file => $file,
231             file_dir => $dir_rel,
232             file_path => "https://github.com/duckduckgo/duckduckgo-documentation/tree/master/duckduckhack",
233             title => $title,
234             category => $category,
235             html => $html,
236             nav_ref => $nav_arr_ref,
237             maintemplate => 'doc.tx',
238             prev => $prev,
239             next => $next,
240             # raw_output => 1, # enable to strip out all of the wrapping for these docs and only output the main content for scraping and inclusion elsewhere
241             };
242              
243             # $ref->{$_} = $html;
244             }, $self->source_dir);
245              
246             # die p($nav_ref);
247              
248             return \%pages;
249             }
250              
251             sub make_anchor {
252             my ($anchor) = @_;
253              
254             $anchor = lc $anchor;
255             $anchor =~ s/[^a-z\s]+//g;
256             $anchor = trim $anchor;
257             $anchor =~ s/\s+/\-/g;
258              
259             return $anchor;
260             }
261              
262             1;
263              
264             __END__
265              
266             =pod
267              
268             =head1 NAME
269              
270             DDG::Publisher::Site::Duckduckhack::Root
271              
272             =head1 VERSION
273              
274             version 1044
275              
276             =head1 AUTHOR
277              
278             Torsten Raudssus <torsten@raudss.us>
279              
280             =head1 COPYRIGHT AND LICENSE
281              
282             This software is Copyright (c) 2012 by DuckDuckGo, Inc. L<http://duckduckgo.com/>.
283              
284             This is free software, licensed under:
285              
286             The Apache License, Version 2.0, January 2004
287              
288             =cut