Joel's Blog

Adventures in Perl 6, part III

Pixelart Camelia

Let’s have a more abstract look at the steps involved when performing a search with p6doc after it’s been invoked:

  1. Parse the search query, e.g. IO::Handle.say;
  2. Find the Pod file(s) containing the desired documentation;
  3. Parse the file to retrieve the Pod data structure, and possibly metadata;
  4. Render the Pod data structure in the desired output format;
  5. Print the rendered output to the console.

In the ‘old’ p6doc, these steps were intermingled, take this example:

sub show-docs(Str $path, :$section, :$no-pager, :$package is copy) {

    my $pager;
    $pager = %*ENV<PAGER> // ($*DISTRO.is-win ?? 'more' !! 'less -r') unless $no-pager;
    if not open($path).lines.grep( /^'=' | '#|' | '#='/ ) {
        say "No Pod found in $path";
        return;
    }
    my $doc-command-str = $*EXECUTABLE-NAME;
    if $section.defined {
        %*ENV<PERL6_POD_HEADING> = $section;
        my $i = findbin() ~ '../lib';
        $doc-command-str ~= " -I$i --doc=SectionFilter"
    } else {
        $doc-command-str ~= " --doc"
    }
    $doc-command-str ~= " $path ";
    if $package.DEFINITE {
        my $cs = ";";
        $cs = "&" if $*DISTRO.is-win;
        $package ~~ s/"Type::"//;
        $doc-command-str = "echo \"In {$package}\"$cs" ~ $doc-command-str;
    }
    $doc-command-str ~= " | $pager" if $pager;
    say "launching '$doc-command-str'" if DEBUG;
    shell $doc-command-str;
}

This routine basically touches steps 3. (without actually retrieving the pod data structure, it’s printed as txt output right away), 4. and 5. while SectionFilter is not a used module, but still part of the perl6/doc repository, and required by the old p6doc.

In general this made it hard to change the code or add features without breaking things.

How it works now

With the new codebase, I aimed to keep steps separate, here’s a basic example:

Find the relevant files.

sub find-type-files(
    Str $type-name,
    $dir,
    --> Array[IO::Path]
)

Process them into Documentable objects.

sub process-type-pod-files(
    IO::Path @files,
    --> Array[Perl6::Documentable]
)

Search through them.

sub type-search(
    Str $type-name,
    Perl6::Documentable @documentables,
    Str :$routine?,
    --> Array[Perl6::Documentable]
)

Print them.

sub show-t-search-results(Perl6::Documentable @results)

There is of course still a lot of room for improvement, but my goal was to make the codebase easier to maintain and to make it easier to add features. Take the search for relevant files and the processing as an example:

In the future, the Perl 6 docs will make complete use of Perl6::Documentable::Registry and caching to process the whole documentation beforehand and build a cache from it. In the new p6doc it will only be necessary to add the new routines for that, and use those new routines to give the Documentable objects to the search itself, instead of finding and processing the files. Everything works on Documentable objects already.

Another door that opens up now is the addition other output formats, just add another show routine and plug it in (like adding another command line option for it), modules for other formats already exist.