CallBackery
view release on metacpan or search on metacpan
lib/CallBackery/Plugin/Doc.pm view on Meta::CPAN
# Perldoc
$app->routes->any(
$root.'/*module' => { module => $index } => sub {
my $self = shift;
# Find module
my $module = $self->param('module');
my $html;
my $cpan = 'http://search.cpan.org/perldoc';
$module =~ s/\//\:\:/g;
# Only ever look up plain module names. Pod::Simple::Search->find splits
# the name on '::' and rejoins the parts with File::Spec->catfile, so a
# name containing '..' would walk out of @INC and render the POD of any
# readable file. Answer 404 without echoing the rejected name back.
return $self->reply->not_found
unless $module =~ /\A\w+(?:::\w+)*\z/;
my $path;
$path = Pod::Simple::Search->new->find($module, @PATHS);
# Redirect to CPAN
return $self->redirect_to("$cpan?$module")
unless $path && -r $path;
# Turn POD into HTML. Three argument open, so that a path can never be
# read as a shell pipe and leading or trailing whitespace is not
# stripped. The open is also checked, as -r above only proves the file
# was readable a moment ago.
open my $file, '<', $path
or return $self->reply->not_found;
$html = _pod_to_html(join '', <$file>);
close $file;
# Rewrite links
my $dom = Mojo::DOM->new("$html");
my $perldoc = $self->url_for($root.'/');
$dom->find('a[href]')->each(
sub {
my $attr = shift->attr;
if ($attr->{href} =~ /^$cpan/) {
$attr->{href} =~ s/^$cpan\?/$perldoc/;
$attr->{href} =~ s/%3A%3A/\//gi;
}
}
);
# Rewrite code sections for syntax highlighting
# $dom->find('pre')->each(
# sub {
# my $attrs = shift->attrs;
# my $class = $attrs->{class};
# $attrs->{class} =
# defined $class ? "$class prettyprint lang-perl" : 'prettyprint lang-perl';
# }
# );
# Rewrite headers
my $url = $self->req->url->clone;
$url =~ s/%2F/\//gi;
my $toc = Mojo::URL->new->fragment('toc');
my $sections = [];
for my $e ($dom->find('h1, h2, h3')->each) {
push @$sections, [] if $e->tag eq 'h1' || !@$sections;
my $anchor = $e->{id};
my $link = Mojo::URL->new->fragment($anchor);
push @{$sections->[-1]}, my $text = $e->all_text, $link;
my $permalink = $self->link_to('#' => $link, class => 'permalink');
$e->content($permalink . $self->link_to($text => $toc, id => $anchor));
}
# Try to find a title
my $title = 'Perldoc';
$dom->find('h1 + p')->first(sub { $title = shift->text });
# Combine everything to a proper response
$self->content_for(perldoc => "$dom");
$self->content_for(index_link => $root.'/');
# $self->app->plugins->run_hook(before_perldoc => $self);
$self->render(
inline => $template,
title => $title,
sections => $sections
);
$self->res->headers->content_type('text/html;charset="UTF-8"');
}
);
return;
}
sub _pod_to_html {
my $pod = shift;
return unless defined $pod;
# Block
$pod = $pod->() if ref $pod eq 'CODE';
# Parser
my $parser = Pod::Simple::HTML->new;
$parser->force_title('');
$parser->html_header_before_title('');
$parser->html_header_after_title('');
$parser->html_footer('');
$parser->index(0);
# Parse
my $output;
$parser->output_string(\$output);
eval { $parser->parse_string_document("$pod") };
return $@ if $@;
# Filter
$output =~ s/<a name='___top' class='dummyTopAnchor'\s*?><\/a>\n//g;
$output =~ s/<a class='u'.*?name=".*?"\s*>(.*?)<\/a>/$1/sg;
return $output;
}
1;
__END__
=head1 NAME
CallBackery::DocPlugin - Documentation Plugin
( run in 0.625 second using v1.01-cache-2.11-cpan-364913b4093 )