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

NAME

Parse::Template - Processeur de templates contenant des expressions Perl

SYNOPSIS

  use Parse::Template;

  my %template = 
    (
     'TOP' =>  q!Text before %%$self->eval('DATA')%% text after!,
     'DATA' => q!Insert data: ! .
               q!1. List: %%"@list$N"%%! .
               q!2. Hash: %%"$hash{'key'}$N"%%! .
               q!3. File content: %%print <FH>%%! .
               q!4. Sub: %%&SUB()$N%%!
    );
 
  my $tmplt = new Parse::Template (%template);
  open FH, "< foo";

  $tmplt->env('var' => '(value!)');
  $tmplt->env('list' => [1, 2, 10], 
              'N' => "\n",
              'FH' => \*FH,
              'SUB' => sub { "->content generated by a sub<-" },
              'hash' => { 'key' => q!It\'s an hash value! });
  print $tmplt->eval('TOP'), "\n";

DESCRIPTION

La classe Parse::Template évalue des expressions Perl placées dans un texte. Cette classe peut être utilisée comme générateur de code, ou de documents appartenant à un format documentaire quelconque (HTML, XML, RTF, etc.).

Le principe de la génération de texte à partir d'un template est simple. Un template est un texte qui comporte des expressions à évaluer. L'interprétation des expressions génère des fragments de textes qui viennent se substituer aux expressions. Dans le cas de Parse::Template les expressions à évaluer appartiennent au langage Perl et sont placées entre deux %%. L'évaluation des expressions doit avoir lieu dans un environnement dans lequel sont définies des structures de données qui serviront à générer les parties à compléter.

             TEMPLATE
          Texte + Expressions Perl
                |
                +-----> Evaluation ----> Texte (document, programme, ...)
                |       
           Subs + Structures de données
            ENVIRONNEMENT

Dans la classe Parse::Template le document à générer est décomposé en parties définies dans un tableau associatif. Le clé dans ce tableau est le nom de la partie, la valeur le contenu associé.

Le tableau associatif est passé en argument au constructeur de la classe :

  Parse::Template->new(SomePart => '... text with expressions to evaluate ...')

L'inclusion d'une sous-partie se fait par mention de la partie dans une expression Perl. Cette inclusion peut se faire en utilisant un style de programmation object ou procédural.

Dans un style object, au sein d'une partie, l'inclusion d'une sous-partie peut se faire au moyen d'une expression de la forme :

  $self->eval('SUB_PART_NAME')

Cette expression doit retourner le texte à insérer en lieu et place. $self désigne l'instance de la classe Parse::Template. Cette variable est automatiquement définie (de même que la variable $part qui contient le nom de la partie du template dans laquelle se trouve l'expression).

L'insertion d'une partie peut également se réduire à l'invocation d'une méthode dont le nom est celui de la partie à insérer :

  $self->SUB_PART_NAME()

Dans un style procédural l'insertion d'une partie se fait par la simple mention du nom de la partie. Dans l'exemple du synopsis, l'insertion de la partie TOP peut ainsi se réécrire comme suit :

  'TOP' => q!Text before %%DATA()%% text after!

DATA() est placée entre %% et est de fait traiter comme une expression a évaluer. Parse::Template se charge de génèrer dynamiquement la routine DATA().

Les routines peuvent être appelées avec des arguments. Dans l'exemple qui suit on utilise un argument pour contrôler la profondeur des appels récursifs d'un template :

  print Parse::Template->new(
           'TOP' => q!%%$_[0] < 10 ? '[' . TOP($_[0] + 1) . ']' : ''%%!
          )->eval('TOP', 0);

$_[0] qui contient initialement 0 est incrémenté à chaque nouvelle inclusion de la partie TOP et cette partie est incluse tant que l'argument est inférieur à 10.

La méthode env() permet de construire l'environnement requis pour l'évaluation d'un template. Chaque entrée à définir dans l'environnement est spécifiée au moyen d'une clé du nom du symbole à créer, associée à une référence dont le type est celui de l'entrée à créer dans cet environnement (par exemple, une référence à un tableau pour créer un tableau). Un variable scalaire est définie en associant le nom de la variable à sa valeur. Une variable scalaire contenant une référence est définie en écrivant 'var'=>\$variable, avec $variable une variable à portée lexicale qui contient la référence.

Chaque instance de Parse::Template est définie dans une classe spécifique, sous-classe de Parse::Template. La sous-classe contient l'environnement spécifique au template et hérite des méthodes de la classe Parse::Template. Si un template est créé à partir d'un template existant, le template dérivé hérite des parties définies par son ancêtre.

En cas d'erreur dans l'évaluation d'une expression, Parse::Template essaie d'indiquer la partie du template et l'expression à incriminer. Si la variable $Parse::Template::CONFESS est à VRAIE, la pile des évaluations est imprimée.

METHODES

new HASH

Constructeur de la classe. HASH est un tableau associatif qui définit les parties du template.

Exemple.

        use Parse::Template;
        $t = new Parse::Template('key' => 'associated text');
env HASH
env SYMBOL

Permet de définir l'environnement d'évaluation spécifique à un template.

env(SYMBOL) retourne la référence assocée au symbole ou undef si le symbole n'est pas défini. La référence retournée est du type indiqué par le caractère (&, $, %, @, *) qui préfixe le symbole.

Exemples.

  $tmplt->env('MY_LIST' => [1, 2, 3])}   Définition d'une liste

  @{$tmplt->env('*MY_LIST')}             Retourne la liste

  @{$tmplt->env('@MY_LIST')}             Idem
eval PART_NAME

Evalue le partie du template désignée par PART_NAME. Retourne la chaîne de caractères résultant de cette évaluation.

getPart PART_NAME

Retourne la partie désignée du template.

ppregexp REGEXP

Pré-processe une expression régulière de manière à ce que l'on puisse l'insérer sans problème dans un template où le délimiteur d'expression régulière est un "/", ou un "!".

setPart PART_NAME => TEXT

setPart() permet de définir une nouvelle entrée dans le hash qui définit le contenu du template.

EXEMPLES

La classe Parse::Template permet de se livrer à toutes sortes de facéties. En voici quelques illustrations.

Génération de HTML

Le premier exemple montre comment générer un document HTML en exploitant une structure de données placée dans l'environnement d'évaluation. Le template comporte deux parties DOC et SECTION. La partie SECTION est appelée au sein de la partie DOC pour générer autant de sections qu'il y a d'élément dans le tableau @section_content.

        my %template = ('DOC' => <<'END_OF_DOC;', 'SECTION' => <<'END_OF_SECTION;');
        <html>
        <head></head>
        <body>
        %%
        my $content;
        for (my $i = 0; $i <= $#section_content; $i++) {
          $content .= SECTION($i);
        } 
        $content;
        %%
        </body>
        </html>
        END_OF_DOC;
        %%
        $section_content[$_[0]]->{Content} =~ s/^/<p>/mg;
        join '', '<H1>', $section_content[$_[0]]->{Title}, '</H1>', 
                  $section_content[$_[0]]->{Content};
        %%
        END_OF_SECTION;
        
        my $tmplt = new Parse::Template (%template);
        
        $tmplt->env('section_content' => [
                                 {
                                  Title => 'First Section', 
                                  Content => 'Nothing to declare'
                                 }, 
                                 {
                                  Title => 'Second section', 
                                  Content => 'Nothing else to declare'
                                 }
                                ]
                   );
        
        print $tmplt->eval('DOC'), "\n";

Génération de HTML par appel de fonctions

Le second exemple montre comment générer un document HTML à partir d'appels imbriqués de fonctions. On souhaite par exemple obtenir le texte :

        <P><B>text in bold</B><I>text in italic</I></P>

à partir de la forme :

        P(B("text in bold"), I("text in italic"))

Les fonctions vont être définies comme des parties d'un template. Au coeur de chaque partie, se trouve l'expression Perl suivante :

        join '', @_

Le contenu à évaluer est le même quel que soit la balise et peut donc être placé dans une variable :

        $DOC = q!P(B("text in bold"), I("text in italic"))!;

        my $ELT_CONTENT = q!%%join '', @_%%!;
        my $HTML_T1 = new Parse::Template(
                            'DOC' => qq!%%$DOC%%!,
                            'P' => qq!<P>$ELT_CONTENT</P>!,
                            'B' => qq!<B>$ELT_CONTENT</B>!,
                            'I' => qq!<I>$ELT_CONTENT</I>!,
                           );
        print $HTML_T1->eval('DOC'), "\n";

La variable $DOC contient la racine de notre template.

Nous pouvons aller un peu plus loin dans la factorisation de la définition des parties du template en exploitant la variable $part qui est définie par défaut dans l'environnement d'évaluation d'un template :

        $ELT_CONTENT = q!%%"<$part>" . join('', @_) . "</$part>"%%!;
        $HTML_T2 = new Parse::Template(
                            'DOC' => qq!%%$DOC%%!,
                            'P' => qq!$ELT_CONTENT!,
                            'B' => qq!$ELT_CONTENT!,
                            'I' => qq!$ELT_CONTENT!,
                           );
        print $HTML_T2->eval('DOC'), "\n";

Enfin, nous pouvons automatiser la production des expressions à partir de la liste des balises HTML qui nous intéressent :

        $ELT_CONTENT = q!%%"<$part>" . join('', @_) . "</$part>"%%!;
        $HTML_T3 = new Parse::Template(
                                  'DOC' => qq!%%$DOC%%!,
                                  map { $_ => $ELT_CONTENT } qw(P B I)
                                 );
        print $HTML_T3->eval('DOC'), "\n";

Pour bénéficier de la possibilité d'utiliser les parties du template comme des procédures, on pourra utiliser la solution qui consiste à hériter de la classe du template créé :

  use Parse::Template;
  my $ELT_CONTENT = q!%%"<$part>" . join('', @_) . "</$part>"%%!;
  my $G = new Parse::Template(
                            map { $_ => $ELT_CONTENT } qw(H1 B I)
                           );
  @main::ISA = ref($G);
  *AUTOLOAD = \&Parse::Template::AUTOLOAD;
  print H1(B("text in bold"), I("text in italic"));

La référence à Parse::Template::AUTOLOAD évite un message indiquant que l'on hérite d'un AUTOLOAD pour définir des appels procéduraux. Pas très élégant.

Génération de HTML par invocation de méthodes

Moyennant une légère transformation il est possible d'utiliser une notation de type invocation de méthode dans l'expression associée aux parties à définir :

        $ELT_CONTENT = q!%%shift(@_); "<$part>" . join('', @_) . "</$part>"%%!;
        $HTML_T4 = new Parse::Template(
                                  map { $_ => $ELT_CONTENT } qw(P B I)
                                 );
        print $HTML_T4->P(
                          $HTML_T4->B("text in bold"), 
                          $HTML_T4->I("text in italic")
                         ), "\n";

Le shift(@_) permet de se débarasser de l'objet template dont nous n'avons pas besoin dans l'expression associée à chaque balise.

Héritage de parties

Dans l'exemple qui suit le template fils $C hérite des parties définies dans son template ancêtre $A :

        my %ancestor = 
          (
           'TOP' => q!%%"Use the $part model and -> " . CHILD()%%!,
           'ANCESTOR' => q!ANCESTOR %%"'$part' part\n"%%!,
          );

        my %child = 
          (
           'CHILD' => q!CHILD %%"'$part' part"%% -> %%ANCESTOR() . "\n"%%!,
          );
        my $A = new Parse::Template (%ancestor);
        my $C = $A->new(%child);
        print $C->TOP();

Le partie TOP définie dans $A est directement invocable sur $C qui est dérivé de $A.

D'autres exemples

Parse::Template a été initialement créée pour servir de générateur de code à la classe Parse::Lex. Vous trouverez d'autres exemples d'utilisation dans les classes Parse::Lex, Parse::CLex et Parse::Token disponibles sur le CPAN.

APROPOS DE LA VERSION EN COURS

N'Hésitez pas à me contacter. Une traduction en anglais d'une version antérieure de cette documentation est disponible dans le répertoire doc.

BUGS

Les instances ne sont pas détruites. Donc n'utilisez pas cette classe pour créer un grand nombre d'instances.

AUTEUR

Philippe Verdret

COPYRIGHT

Copyright (c) 1995-2001 Philippe Verdret. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 223:

Non-ASCII character seen before =encoding in 'évalue'. Assuming CP1252