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 )