=begin rakudoc :type<fundamental>
=TITLE Templates for RakuDoc-Render
=SUBTITLE Snippets to customise RakuDoc blocks
=for AUTHOR :hidden
Richard Hainsworth aka finanalyst

=for VERSION :hidden
v0.2.1

=head1 Overview

RakuDoc-Render (RR) uses I<plugins> to customise blocks. A plugin will
add custom data and templates to an instance of an RR B<processor>.

The templates are added to an instance of the B<Template-directory> class held
within the I<processor>.

The custom data is also added to the I<processor>'s B<Template-directory> object.

Helper callables that can be used inside a template can also be added to the
I<processor>'s B<Template-directory> object.

Within a template, all the registered templates, the custom data of the I<processor>,
and the helper callables can be accessed. See L<helper callables|#Calling a helper callable> for more
information.

When a template is added to a I<Template-directory> and the template name
already exists, the old value is pushed onto a stack, and can be accessed.

A generic RakuDoc::Processor will populate the I<Template-directory> with
text templates that then served as the generic defaults.

When a template is added to the directory, the C<source> attribute on the B<Template-directory>
is set, and copied into each template. In this way, the origin of a template can be traced.

When the C<debug> attribute on the B<Template-directory> is True, the name and origin of
each Template is reported whenever a Template is called.

=head1 Templates

A I<Template-directory> object is an extended Hash structure.

Templates are specified as a list of Pairs of the form
=begin code :lang<text>
    # psuedocode
    <key> => -> <Hash>, <Template object> <Block>
    # or as an example
    head => -> %prm, $tmpl { ... }
=end code
where
=item key is a string and serves as the name of the template
=item C<%prm> is an ordinary Hash of the parameters that are accessed inside the block
=item2 In order to access 'contents', the code inside the block would be C< %prm<contents> >
=item2 The name of the Hash parameter is arbitrary, but conventionally is called C<%prm>.
=item C<$tmpl> is a I<Template> object, see below, and conventionally is called C<$tmpl>.
=item The contents of the block is a normal Raku program and should return a Str or PStr (see below).
=item2 The block shown above is the I<pointy> form, so the object returned is the value of the last statement
=item2 If the Raku program in the block is more easily written using a C<return> statement, then
a C<sub> form should be used, eg.

    key => sub ( %prm, $tmpl ) { ... }

=head1 Custom data

A I<Template-directory> object also has a C< %.data > structure, which is intended for use by plugins
that need to make extra data available for templates.

For example, suppose a custom block is written to include data about all the documents in a website,
and the information is collected into a structure called C<%files>, which is to be available to
the template C<listfiles>, then we could have
=begin code
    my %temp-dir is Target-directory = listfile => -> %prm, $tmpl {
        my %file-data = $tmpl.globals.data<listfiles>
        # code to create the output string using the data
    }

    # somewhere later
    %temp-dir.data<listfiles> = %files;
    # use the template
    my $rv = %temp-dir<listfile>;
=end code

The C<%temp-dir> object, which is an instance of the I<Template-directory> class,
provides access to the data through the C<.globals> attribute of the I<Template> object.

=head1 Template object

The Template object contains a reference to the Template-directory object, so all the templates registered
with the RakuDoc processor, and all the data attached to it, can be accessed.

Inside the Raku block of a new template, the following methods can be used on the C<$tmpl> object.

=head2 method B<$tmpl.prev>

This calls the previously defined block of the template with the same name, with the same parameters provided to current block.
The use case is to allow some pre- and (limited) post- processing of the parameters while keeping the previous template.

B<Pre-processing> Suppose a new template is required that merely adds the word 'Chapter' to the contents of a C<=Chapter> block. So the
parameter needs to be preprocessed and the previous template called. Assuming %prm<contents> is a Str.

    chapter => -> %prm, $tmpl {
        %prm<contents> = 'Chapter ' ~ %prm<contents>;
        $tmpl.prev( %prm ); # pass the new value of contents
    }

B<Post-processing> For example, suppose a template 'table' has been defined, but a new template is needed that substitutes the HTML class,
then some post-processing of the old template is sufficient, eg.,
=begin code
    table => -> %prm, $tmpl {
        ($tmpl.prev).subst( / '<table' \s+ 'class="pod-table' /, '<table class="table is-centered')
    }
=end code
This assumes that the return object from both templates I<chapter> and I<table> is a Str, which it could be. But generically,
it is best not to assume this. A fuller example is given below.

=head2 Calling a helper callable

Suppose a template generates objects that need to be added to the Table of Contents (ToC).
The ToC structure is collected by the Renderer leaf by leaf, and the order of the
leaf data is constructed because the order of the ToC is important.

So the code in the template block can call
=begin code
    $tmpl.globals.helper<add-to-toc>(
        :caption<...>, :target<...>, :level(1)
    )
=end code

=head2 Calling the escape method

Each output (eg HTML or MarkDown) may have its own escape method. The escape method can be called within
a template as follows:
    $tmpl.globals.escape.( $string-to-be-escaped )

=nested Note the C<.> after C<escape>. This is to ensure the string is passed to the block.

=head2 Calling another defined template

The block registered with key C<aaa> can be called inside another template block, with or without parameters.

I<Without parameters>, eg C<$tmpl<aaa>> or B<$tmpl('aaa')> the other template block is called with the same parameters, eg
=begin code
    page => -> %prm, $tmpl {
        $tmpl<header> ~ $tmpl<body> ~ $tmpl<footer>
    }
=end code
where C<header>, C<body>, and C<footer> are all registered in the I<RR> processor.

I<With parameters>, eg. C<$tmpl('aaa', %( :attr(1), :new-attr<some string> ) )>,
the block registered with the key C<aaa> is called with the new set of parameters specified in the
Hash. It can be used to provide a subset of parameters, or to rename the parameters for a different
template.

=head1 Template information and debugging

Four attributes can be set on a C<Template-directory> object to aid with debugging templates,
especially when templates have content that is derived from other templates:
=item B<debug>
=item B<verbose>
=item B<test>
=item B<pretty>

=head2 C<.debug> attribute

When set to True, eg
=nested
my Template-directory %template-dir;
# assign some templates to %template-dir
%template-dir.debug = True;

information about the name of the template being used, and the source of the template
is sent to STDOUT via C<say>. This is used by the C<debug(Templates)> command in a C<Rakudoc::Processor> object.

The information generated is for the registered template, not to be confused with the C<.test> or C<.pretty> attributes.

=head2 Verbose output of one template

The C<Template-directory> class has a C<.verbose> attribute.
When set to a string corresponding to the name of a template, eg.
=begin code
    my Template-directory %template-dir = %(
        one => -> %prm, $tml { 'Hello world' },
        two => -> %prm, $tml { 'Not again' },
    );
    # later ...
    %template-dir.verbose = 'one';
=end code
the verbose result of that template (eg. 'one') will be sent to
STDOUT via C<say>.

The output of only one template at a time is supported at the moment.

=head2 The C<.test> attribute

When this attribute is set for the Template-directory object, eg.
=begin code
    my Template-directory %template-dir;
    # assign some templates to %template-dir
    %template-dir = %(
        aaa => -> %prm, $tmpl {
            'orig: ' ~ %prm<contents>;
        },
        ggg =. -> %prm, $tmpl {
            %prm<contents> = 'Chapter ' ~ %prm<contents>
        }
    );
    %template-dir.test = True;
=end code
In order to test the template with a set of unit tests, it is important for the results of the
template to be uniform and predictable.

Also the renderer will call the template with options defined at run time, eg., because of
a C<=config> directive.

The output from a template when C<test> is True does not depend on the block registered with the template.
Instead, all the options (which may include the output from other templates) are returned in alphabetical
order.

For example, the result of calling the templates defined above, with C<test=True>, where the
output from one template is contained in another, will be:
=begin code
    say %template-dir<aaa>(%(
        :contents<something>,
        ggg => %template-dir<ggg>(%(:contents<more stiff>,)),
    ));
    # output
    <aaa>
    contents: ｢something｣
    ggg: ｢<ggg>
    contents: ｢more stiff｣
    </ggg>
    ｣
    </aaa>
=end code
It does not matter I<how> the templates were defined, but it does matter that they B<were> defined.
Calling a template that is not registered in the B<Templated-directory> object will cause an error.

=head2 The C<.pretty> attribute

When this attribute is set for the Template-directory object, eg.
=begin code
    my Template-directory %template-dir;
    # assign some templates to %template-dir
    %template-dir = %(
        aaa => -> %prm, $tmpl {
            'orig: ' ~ %prm<contents>;
        },
        ggg =. -> %prm, $tmpl {
            %prm<contents> = 'Chapter ' ~ %prm<contents>
        }
    );
    %template-dir.pretty = True;
=end code
the output is similar to the C<.test> attribute, which it overrides, but white space is added to
make the content structure clearer.

For example,
=begin code
    say %template-dir<aaa>(%(
        :contents<something>,
        array => <one two three four>,
        hash => ( <eight nine ten> Z=> 1..* ).hash,
    ));
    # output produced
    <aaa>
      array: ｢List=(
            "one",
            "two",
            "three",
            "four"
      )｣
      contents: ｢something｣
      hash: ｢Hash={
            :eight(1),
            :nine(2),
            :ten(3)
      }｣
    </aaa>
=end code
=place semantic:AUTHOR :caption<Credits>
=place semantic:VERSION :!toc

=end rakudoc