The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 NAME

dTemplate - A simple yet powerful template handling logic with advanced
features.

    $Id: dTemplate.pod 105 2004-07-24 12:08:22Z dlux $

    $URL: http://svn.dlux.hu/public/dTemplate/trunk/dTemplate.pod $

=head1 SYNOPSIS

    use dTemplate;

    # definition 

    $mail_template = dTemplate->new( file => "mail_tmpl.txt" );

    $template = dTemplate->new( text => "<html>$BODY$</html>" ),



    # parsing
    $mail = $mail_template->parse(
        FROM    => {
            first_name => "Balazs",
            last_name  => "Szabo",
            email      => "dlux@dlux.hu"
        },
        TO      => "foo@bar.com",
        SUBJECT => $subject,
        BODY    => 
            sub { $email_type==3 ? $body_for_type_3 : $body_for_others },
        SIGNATURE=> $signature_template->parse( KEY => "value" )
    );

    print "Please send this mail:\n$mail";

where mail_tmpl.txt is:

        From    : "$FROM.first_name$ $FROM.last_name$" <$FROM.email$> 
        To      : $TO$
        Subject : $SUBJECT$

        Message body:
        $BODY$

        $SIGNATURE$

    ### Advanced feature: Styling

    # Style definition
    $style= { lang =>'hungarian', color=>'white' };

    # Selector definition
    $html_template = dTemplate->new(choose => $style,
        'hungarian+white' => 
            dTemplate->new(file => "hun_white_template.html"),
        'spanish'         => 
            dTemplate->new(file => "spanish.html"),
        'black+hungarian' => 
            dTemplate->new(file => "hun_black_template.html"),
        'english'         => 
            dTemplate->new(file => "english_template.html"),
        'empty'           => 
            "<html>This is a text, $BODY$ is NOT substituted!!!!"</html>",
        # default:
        ''                => 
            dTemplate->new(text => "<html>$BODY$</html>"),
    );

    # Selector definition
    $body_template = dTemplate->new(choose => $style,
        'hungarian'       =>  
            dTemplate->new(file => "sziasztok_emberek.html"),
        'spanish'         =>  
            dTemplate->new(file => "adios_amigos.html"),
        # default:
        ''                =>  
            dTemplate->new(file => "bye_bye.html"),
    );

    print  $html_template->parse(BODY  =>  $body_template->parse());
        # will  print  "sziasztok_emberek.html"  in  the
        # "hun_white_template.html"

    %$style = ();
    print $html_template->parse(BODY => $body_template->parse());
        #  will print "bye_bye.html" surrounded by "<html>" and "</html>" tags.

    %$style = ( lang => 'english' );
    print $html_template->parse(BODY => $body_template->parse());
        # will print the "bye_bye.html" in of the "english_template.html"

    ### Advanced feature: Changing placeholder special characters:

    $dTemplate::START_DELIMITER     = '<%\s*'; # default: \$
    $dTemplate::END_DELIMITER       = '\s*%>'; # default: \$
    $dTemplate::VAR_PATH_SEP        = '\/';    # default: \.
    $dTemplate::PRINTF_SEP          = '\$';    # default: %+
    $dTemplate::ENCODER_SEP         = '\@';    # default: \*+
    $dTemplate::ENCODER_PARAM_START = '\(';    # default: \/
    $dTemplate::ENCODER_PARAM_END   = '\)';    # default:

    # dTemplate 2.2 Compatibility:
    $template1 = define dTemplate "mail.txt";

    $template2 = text dTemplate "This is the template text...";

    $template3 = choose dTemplate \%hash, ...;

=head1 DESCRIPTION

This module is aimed to be a fast, general-purpose, lightweight but easily
extendible templating system.

With this module, you can write template-parsing routines in the way the
templates are structured logically: starting from outside to inside. Your
code will be clear, well-structured and easy to understand. This logic can
be attained using by inline subroutines as values of template variables.
(Look at the example at the end of the document)

=head1 USAGE

A template is a text data (usually taken from a file), which contains
special placeholders for variables.. A template object (a
dTemplate::Template object) is basically the representation of this text
data. The "placeholders" contain informations about:

=over 4

=item *

What data to be written into the placeholder: the name and the "path" of
the variable.

=item *

How the data is to be formatted and processed. 

=back

=head2 The format of a placeholder

A placeholder in a text file has the following format: (the format can be
customized, see below)

  $varname%printf_def*encoder_def$

, where:

=over 4

=item varname

It is the name of the variable, which can be any string with alphanumeric
characters. The "." in the varname has a special meaning, see the "Data
Lookup" section below.

=item %printf_def

This is an optional part. Used only, when you want to format the output by
printf before substitution.  You can use as many '%' as you want here, it can be
used to pad the variable, for example when your output is a table. E.g:

  $MONEY%%%%%%011d$

is a valid placeholder.

=item *encoder_def

Encoders are specifal subroutines, which are used, to process a data before
substitution. They works like "pipe" in UNIX. They got the data in the first
parameter, and the return value will be substituted. They can be chained,
so more than one encoder can be used for one value. In this case the
encoders will be executed in the order of definition.

Encoders are separated with "*", and can have one parameter, which is
separated with "/" from the encoder name.

There are some built-in encoders in dTemplate:

    - u          : url-encoder
    - h          : HTML-encoder (converts > to &gt;, etc)
    - ha         : Advanced HTML encoder (\n => <BR>, tabs => spaces)
    - uc         : convert the string to uppercase
    - lc         : convert the string to lowercase
    - eq/par     : returns true if the encoded string is "par"
    - if/par     : returns "par" if the encoded string is true
    - printf/par : returns printf formatted data, where "par" is the format
                   string

Chaining of the encoders:

    $TITLE*uc*h$

or

    $weight*eq/7*if/CHECKED$

(the last example returns CHECKED if the weight is equal to "7", useful for
radio-buttons or drop-down menus in HTML)

Read more on encoders (and how to make new encoders) in the Encoders part.

=back

=head2 Template objects

There are three ways to create template objects

From a file:

    $template = dTemplate->new( file => $filename );

From a scalar variable:

    $template = dTemplate->new( text => "<html>$BODY$</html>" ),

Using the template chooser:

    $template = dTemplate->new( choose => $style_hash_ref,
        "style1" => $dTemplate_object1,
        "style2" => $dTemplate_object2,
        ...
    );

Note, the template chooser is not a "real" template object. It is a
meta-object (a dTemplate::Choose object), which selects one of many real
template objects based on the contents of a style hash. Read more about the
chooser later.

=head2 Parsing

Once you have the template object, you can use them to create output by
substituting and formatting data into the placeholders.

The parsing is done by the objects' parse methods. The return value of the
parse method is the substituted text.

The variable substitution is done in following steps:

    - Look for the data to substitute
        - Look for the data among the parameters of the parse method.
        - Look for the data among the parameters of the template
          object's parse hash ($obj->parsehash->{$varname})
        - Look for the data among the keys of %dTemplate::parse hash
    - Process "path" information in the placeholder
    - If we have not found the variable, then we use the value of the ""
      key of the object's parsehash ($obj->parsehash->{""}) if exists, or
      the $dTemplate::parse{""} if exists.
    - If the value is a code reference, then we call it to return the
      value.
    - Use the encoders on the returned value
    - Use the printf-formatter on the returned value

=head2 Looking for the data to substitute

Each substitution is started by looking up the substitutable variable name.
If the variable name contains path information (contains "." characters),
then, it is not used at this step, so only the information before the first
"." is used.

The parse method looks for the substitutable variable name in three places:

    - Among the parameters of the parse method
    - Among the keys of local parsehash ($object->parsehash)
    - Among the keys of dTemplate::parse hash

=head2 Looking for the data in the parameters of the parse method

The parse method can have parameters in the following format:

    - List of name => value pairs
    - Hash-reference.

For example:

    my $hashref = {
            name2 => $value2, 
            name3 => $value3
    };

    $template->parse(
        name => $value,
        $hashref,
        name4 => $value4,
        { name5 => $value5 },
        ...
    )

This method call defines "name", "name2", "name3", "name4" and "name5"
variable names, so they will be substituted in the $template object with
$value, $value2, $value3, $value4 and $value5.

=head2 Looking for the data in the local parsehash

If we encounter a variable reference in the template placeholders, that is
not assigned among the parameters of parse method, then we look up the
variable in keys of the local parsehash of the dTemplate object. You can
assign values to the local parsehash with the following expression:

    $obj->parsehash->{key} = $value;

or you can assign hash-reference to multiple objects:

    $obj1->parsehash = $obj2->parsehash = { key1 => "v1", key2 => "v2" };

If we found it, then we use its value for further processing.

=head2 Looking for the data in the dTemplate::parse hash

If we did not find the variable even in the local parsehash, then we look
up the variable in keys of the global dTemplate::parse hash. If we found
it, then we use its value for further processing.

=head2 Processing "path" information

After we have found the variable in the previous phase among the parameters
of the parse method or in the dTemplate::parse hash, we process the "path"
information in the placeholder if we have it.

Path information is appended to the variable name by "."-s.

If the variable definition in the placeholder contains "path", then we
assume that the variable is a hash-reference, and we tries to access the
specified hash key in it. For example in $template, you define the
following placeholder:

    $name3.key1.key2$

If you assign $value3 to name3 (in the parameter-list of the parse method
or in the $dTemplate::parse{name3} hash), then it is not simply substitute
$value3, but it tries to use the $value3 as a hash reference, and looks up
a key in it with the name "key1". If it is found, then it tries to use the
value as a hash reference, and looks up a key in it with the name "key2",
and its value will be substituted:

    $value3 = { key1 => { key2 => "This will be substituted" } };

If the value, which is found is a code reference, then we stop the
key-lookup and call the sub e.g:

    $value3 = { key1 => sub { return "This will be substituted"; } }

=head2 Using data in $obj->parsehash->{""} as value

If we did not find the referenced value by the process described above,
then we use the the value of the "" hash-key of the object's parsehash instead
of the variable. If it is a code-reference, then it is called exactly like
it was the variable that has found, e.g:

    $obj->parsehash->{""} = sub { "Fallback value for this template"; }

=head2 Using data in $dTemplate::parse{""} as value

If we did not find the referenced value by the process described above,
then we use the the value of $dTemplate::parse{""} hash-key instead of the
variable. If it is a code-reference, then it is called exactly like it was
the variable that has found.

=head2 Calling code references

We can assign code references to variables, they will be called if we
encounter the variable, which needs substitution.

The function-call will have the following parameters:

    - Full matched placeholder as the first argument
    - An array reference to the splitted variable and path information as a
      second argument.
    - The dTemplate::Template object in which you called the "parse"
      method.

For example if a placeholder is like to this:

    $HASH1.key1.key2*uc$

and the parsing code is the following:

    $t1->parse(
        # ...
        HASH1 => sub { my ($placeholder, $pathref, $object) = @_;
            warn "Placeholder: $placeholder, Variable path:".@$pathref."\n";
            # ...
        }
    );

Then it will print the following message to the standard error:

    Placeholder: $HASH1.key1.key2*uc$, Variable path: HASH1 key1 key2

=head2 Calling encoders

If we have the data, which substitutes the placeholder, then we can encode
them or format them by the dTemplate encoders. The encoders are code
references, which are assigned the the values of the %dTemplate::ENCODERS
hash. Names of the encoders are the keys of the hash.

Encoders are called in the order of declaration in the template, so

    $variable*uc*h$

is not the same as

    $variable*h*uc$

An encoder can have one optional parameter, which can be provided in the
placeholder, e.g:

    $weight*eq/7*if/CHECKED$

(the last example returns CHECKED if the weight variable is equal to "7",
useful for radio-buttons or drop-down menus in HTML)

Note, that by default, the encoders are NOT called, if we did not find the
variable and we are using the local key of the local parsehash or
$dTemplate::parse. This is a feature, not a bug, because the "" keys
are designed to be used only to report errors or warnings, like this:

    use Carp qw(cluck);
    $dTemplate::parse{""} = sub {
        cluck "$_[0] is not assigned";
        return "";
    }

If you want to use the $dTemplate::parse{""} value (or the local
parsehash's "" key) as it was a normal value, then set the
$dTemplate::NOTASSIGNED_MODE variable to true. In this case, the encoders
and the formatter are called on the value of $dTemplate::parse{""} also.

For example, if the $dTemplate::parse{""} is assigned to the subroutine
above, and if $dTemplate::NOTASSIGNED_MODE is false (by default), the

    $noassigned_variable%03d$

will be substituted with an empty string, but if it is true, it is
substituted to "000" (because the formatter is called).

The parameter-list of an encoder if it is called:

  - The encodable text
  - The (optional) encoder parameter
  - The dTemplate::Template object in which the parsing is done

=head2 Changing placeholder special characters

You can change the placeholder parameters by changing (or localizing) the
following variables.

    $dTemplate::START_DELIMITER     = '\$';
    $dTemplate::END_DELIMITER       = '\$';
    $dTemplate::VAR_PATH_SEP        = '\.';
    $dTemplate::PRINTF_SEP          = '%+';
    $dTemplate::ENCODER_SEP         = '\*';
    $dTemplate::ENCODER_PARAM_START = '\/';
    $dTemplate::ENCODER_PARAM_END   = '';

If you change these variables, then these are used in the compilation of the
following templates. Currently there is no supported way to recompile an
already compiled template, so you need to create a new instance.

Although if you want to compile a variable, which is not compiled, then you
can call the $template->compile method on them by hand.

These variables can be set to any regular expressions, not just one single 
character.

If you don't want to use any of the features, then set the corresponding
variable to any regexp that is too complex to be true.

=head2 Styles (Template choosers)

You can use the "chooser" to dynamically select one template from many
based on styles.

The current "style" is represented by a hash, for example:

  my %style = (lang => 'spanish', color => 'white');

Based on informations in the hash, the chooser (which is a
dTemplate::Choose object) decides which dTemplate::Template object is used
in the parse operation.

dTemplate::Choose object also has a parse method, and it is compatible with
the parse method of dTemplate::Template, so you can use it transparently.

When you define a template chooser object in the following way:

    $template = dTemplate->new( choose => \%style,
        "style1" => $dTemplate_object1,
        "style2" => $dTemplate_object2,
        "style3" => $dTemplate_object3,
        "style3+style4" => $dTemplate_object4,
        ...
    );

, then you get a wrapper object, which wraps several dTemplate::Template
objects, which selects $dTemplate_object1 if "style1" is active,
$dTemplate_object2 if "style2" is active, $dTemplate_object3 if "style3"
and "style4" is active, etc.

If you call the "parse" method of this template, then it selects one of the
dTemplate objects ($dTemplate_object1, $dTemplate_object2, etc.) and calls
the parse method of them.

The chooser selects the template, which has the most "style" matched.

For example if the style hash is:

    %style = (first_style => "style3", second_stype => "style99");

Then

    $template->parse(...)

calls the parse method of $dTemplate_object3, but if

    %style = (first_style => "style3", second_stype => "style4");

then it activates the $dTemplate_object4.

Note, that the keys in the %style hash has no meaning.
    
=head1 COMPATIBILITY

=head2 Old-style constructors

Old-style constructors ("define dTemplate", "choose dTemplate", "text
dTemplate") is obsoleted, but still can be used. The preferred way to call
the "new" method in new programs.

=head2 Prior 2.3

dTemplate v2.3 removes the default value of $dTemplate::parse{""}. In the
pre 2.3 versions, $dTemplate::parse{""} was a code reference, which
returned the first parameter of it.

=head1 HINTS

=head2 Template compilation

In the first parse of every template, the templates will be compiled. 
It is used to speed up parsing.

=head2 %dTemplate::parse localization

Don't forget that %dTemplate::parse can be localized. This means you can 
define local-only variable assignments in a subroutine:

  local %dTemplate::parse = ( 
      %dTemplate::parse, 
      local_name => $value 
  );

=head2 References and encoders

You don't need to use text as the input value of an encoder, you can
use any scalar, even references! If you want (for example) print a date by
a date encoder, which expects the date to be an array ref of [ year, month,
day ], then you can do this, e.g:

   $dTemplate::ENCODERS{date} = sub {
       return "" if ref($_[0]) ne 'ARRAY';
       return $_[0]->[0]."-".$_[0]->[1]."-".$_[0]->[2];
   }

Then, when you put $START_DATE*date$ to a template, you can parse this template:

  $template->parse(
    START_DATE => [2000,11,13],
    ...
  );

=head2 Magical (tied) hashes

You can use magical hashes everywhere in the "parse" method parameter list,
where you can use normal hashes, but because I redesigned the "parse"
method with the speed with the first priority, it works quite a bit
different than the older ( <= 2.0 ) versions. 

At template-compile time, the "compile" method collects the variable names, 
which are found in that template, and the "parse" method knows which 
variables are required for processing this template.

When the "parse" method realizes that a parameter is a hash reference, 
then it always tries all the remaining template variables (which are not 
assigned in the preceding part of the parameter list) in that hash reference.

Imagine the following situation:

  $template->parse( name => "blow", \%hash);

... where %hash is a magical hash, and the $template contains the "name",
"address" and "method.type" variables. When the parse method meets with the
\%hash, the "name" is already assigned, so it olny tries to read the
$hash{address} and $hash{method} variables.

This is not a problem with normal hashes, but if you use magical hashes, you
may have a very expensive FETCH function, and this effect can cause problems.

There are two way to work around it:

=over 4

=item *

Use qualified variable names. If you use the following form of parse:

  $template->parse( name => "blow", data => \%hash);

... then the %hash is called only when the template parser finds the
"data.address" and "data.method.type" variable references in the template. Of
course, you have to change the template variable names also.

=item *

Use the hash instead of a hash reference:

  $template->parse( name => "blow", %hash);

In this case, the magical hash is iterated through when the parameter list
is assembled. This is better only if you are afraid of random
key retrieval, but it can be also slow, if the FIRSTKEY, NEXTKEY and FETCH
operations are slow.

But if the random-key retrieval is not a problem for your magical hash, 
then use the default form instead of this, because that requires less
operation (only one FETCH).

=back

=head1 EXAMPLE

It is an example, which contains most of the features this module has. It is not
intended to be a real-world example, but it can show the usage of this module.

This example consists of one program, and some template modules.

The executable version of this program can be found in the example
directory of the module distribution.

  use dTemplate;

  ### definition of the standard templates

  my @TEMPLATE_LIST=qw(page table_row table_cell);
  my $templates={};
  foreach my $template (@TEMPLATE_LIST) {
    $templates->{$template} = 
      define dTemplate("templates/$template.htm");
  }

  ### definition of the styled templates (styles = languages)

  my @STYLES=qw(eng hun);
  my @STYLED_TEMPLATE_LIST=qw(table_title);

  my $style_select={ lang => 'hun' }; 

  foreach my $template (@STYLED_TEMPLATE_LIST) {
    my @array=();
    foreach my $style (@STYLES) {
      push @array, $style => 
        define dTemplate("text/$style/$template.txt");
    }
    $templates->{$template} = 
      choose dTemplate $style_select, @array;
  }

  ### setting up input data

  my $table_to_print=[
    [ "Buwam",   3, 6, 9 ],
    [ "Greg",    8, 4, 2 ],
    [ "You're",  8, 3, 4 ],
    [ "HTML chars: <>", 3],
  ];

  ### setting up the global parse hash with parse parameters;

  $dTemplate::parse{PAGENO}=7;

  ### settings up a hash with personal data.

  my $person_hash={
    name => { first_name => "Greg" },
    zip  => "9971",
  };

  ### this hash is simply added to other parse parameters

  my $parse_hash={
    "unknown" => { data => 157 },
  };

  ### the main page parse routine

  print $templates->{page}->parse(
    TABLE_TITLE =>             # name => value pair
      $templates->{table_title}->parse(),
    TABLE => sub {             # name => value pair. value is a sub
      my $ret="";
      foreach my $row (@$table_to_print) {
        $ret .= $templates->{table_row}->parse(
          BODY => sub {
            my $ret="";
            foreach my $cell (@$row) {
              $ret .= $templates->{table_cell}->parse(
                TEXT => $cell,
              )
            }
            return $ret;
          }
        )
      }
      return $ret;
    },
    "person" => $person_hash,  # name => value pair. value is a href
    $parse_hash,               # only a hash with parse parameters
  );

And the templates:

=over 4

=item templates/page.htm:

  <html>
  <body>

  <h1>$TABLE_TITLE*h$</h1>

  <table>
  $TABLE$
  </table>

  <br>
  Person name: $person.name*h$, zip code: $person.zip*h$
  <br>

  Unknown data: $unknown.data*h$
  <br>

  Page: $PAGENO%02d*h$

  </body>
  </html>

=item templates/table_row.htm:

  <tr>$BODY$</tr>

=item templates/table_cell.htm:

  <td>$TEXT*h$</td>

=item text/eng/table_title.txt:

  Table 1

=item text/hun/table_title.txt:

  1. táblázat

=back

=head1 COPYRIGHT

Copyrigh (c) 2000-2001 Szabó, Balázs (dLux)

All rights reserved. This program is free software; you can redistribute it 
and/or modify it under the same terms as Perl itself.

=head1 AUTHOR

dLux (Szabó, Balázs) <dlux@kapu.hu>

=head1 SEE ALSO

perl(1), HTML::Template, Text::Template, CGI::FastTemplate, Template.

=cut