Prise en main

Écrire sa première page, et les six points qui surprennent au début.

Où le code s'exécute

Le moteur Joodo est un exécutable CGI placé derrière Apache. Le serveur lui confie les fichiers .do par un couple de directives de la forme :

AddHandler cgi_joodo .do
Action     cgi_joodo "/joodo/cgi_joodo"
DirectoryIndex index.do index.html

À chaque requête, le moteur compile la page demandée puis l'exécute et renvoie le résultat. Il n'y a rien à compiler à l'avance ni à redémarrer après une modification : enregistrer le fichier suffit.

Votre première page

Créez essai.do dans un répertoire servi par Apache :

<h1>Essai</h1>
<p>Bonjour $$v:Nom, nous sommes le $$s:date.</p>

<%
var Nom;
Begin
Nom := Parms('nom');
If Nom = '' Then Nom := 'inconnu';
SetVars('Nom', HtmlEncode(Nom));
End.
%>

Appelez essai.do?nom=Camille. Trois choses se sont produites : le bloc principal a lu le paramètre de l'URL avec Parms et l'a rangé dans une variable, puis le HTML a été envoyé en remplaçant $$v:Nom par cette variable et $$s:date par la date du jour.

L'ordre d'exécution

C'est le point le moins intuitif, et il vaut la peine de s'y arrêter tout de suite : le bloc principal s'exécute en premier, avant que la moindre ligne de HTML ne soit envoyée — même s'il est écrit tout en bas du fichier, comme ci-dessus.

  1. le bloc principal BeginEnd. ;
  2. puis __top.inc s'il existe, puis le HTML de la page et les blocs Script, dans l'ordre du fichier.

Une page se lit donc comme un contrôleur suivi d'une vue. Le bloc principal décide : il lit la requête, redirige, prépare les données. La mise en page vient ensuite et se contente d'afficher.

Conséquence pratique : n'affichez pas depuis le bloc principal. Un EchoChar qui s'y trouve sortira avant tout le reste de la page, y compris avant la balise <html>. Pour afficher au milieu de la mise en page, utilisez un bloc Script.

La structure d'une page

Les déclarations viennent d'abord, le bloc principal ensuite, terminé par End. — avec un point.

<%
include 'outils.inc';       { fichiers partagés }

var Total, Ligne;           { variables }

function Tva(Montant);      { fonctions }
Begin
Result := Montant * 20 / 100;
End;

Begin                       { bloc principal }
Total := '100';
SetVars('Tva', Tva(Total));
End.
%>

Pour afficher au milieu de la mise en page, on intercale un bloc Script : il s'exécute là où il est écrit, dans le flux de la vue, avec ses propres variables locales.

<div class="encadre">
  <%
  Script;
  var S;
  Begin
  LoadFromFile('journal.log', S);
  EchoChar(StringReplace(S, #10, '<br>'));
  End;
  %>
</div>

Les six points qui surprennent

1. Tout est chaîne

Il n'y a qu'un seul type. Les nombres, les dates et les booléens sont des chaînes que les opérateurs et les fonctions interprètent selon le contexte. Un booléen vaut '1' ou '0'.

2. L'opérateur + est ambigu

C'est le piège le plus fréquent. + concatène si l'un des opérandes est un littéral chaîne, et additionne sinon — décidé à la compilation, sur la forme du texte.

EchoChar('Total : ' + 42);   { concaténation -> "Total : 42" }

A := '40';
B := '2';
X := A + B;                  { addition -> 42, et non "402" }
X := Concat(A, B);           { "402" }

À retenir : pour concaténer deux variables, utilisez Concat. C'est sans ambiguïté et ça se relit.

3. Les structures sont des clés aplaties

A[3] et C.nom désignent des clés composées, pas des tableaux ni des enregistrements. Conséquence : B := A ne copie pas la structure, seulement la valeur de la racine.

C.nom := 'Dupont';
C.adresse.ville := 'Lyon';

ObjectCopy(A, B);            { copier réellement un sous-arbre }

Les fonctions qui produisent une structure suivent la même convention : la racine reçoit le nombre d'éléments.

jsonToObject('[{"nom":"Durant"},{"nom":"Martin"}]', A);
{ A vaut '2', A[0].nom vaut 'Durant' }

For I := 0 To A - 1 Do EchoChar(A[I].nom + '<br>');

jsonToObject charge indifféremment un objet seul ou une collection entière : c'est la seule fonction à connaître pour le JSON.

4. Les boucles SQL ont leur idiome

SqlFirst indique s'il existe au moins une ligne, SqlNext rend '0' sur la dernière. Eof ne s'applique pas aux requêtes : c'est une fonction de fichier.

SqlAssignDb(Q, Vars('Db'));
SqlQuery(Q, 'select nom from clients');

If SqlExec(Q) Then
  If SqlFirst(Q) Then
    Repeat
      EchoChar(SqlField(Q, 'nom') + '<br>');
    Until Not SqlNext(Q);

SqlFree(Q);

Une requête s'ouvre toujours par SqlAssignDb, qui dit explicitement sur quelle base elle porte — presque toujours celle de la session courante, rangée dans Vars('Db').

5. Echo substitue les $$

Dans le HTML comme dans ce qu'affiche Echo, le moteur remplace $$v:nom par une variable, $$p:nom par un paramètre de requête, $${texte} par une traduction. Pratique pour les gabarits, gênant pour du JSON.

<p>Bonjour $$v:prenom, nous sommes le $$s:date.</p>

Quand la donnée peut contenir $$, utilisez CrudeEchoChar, qui n'applique aucune substitution.

6. La compilation se fait en une passe

Tout doit être déclaré avant d'être utilisé : une fonction appelée plus haut qu'elle n'est écrite ne compile pas. C'est aussi pourquoi les fonctions partagées se placent dans un fichier inclus.

Deux fichiers sont d'ailleurs inclus automatiquement s'ils existent dans le répertoire de la page, sans rien avoir à déclarer :

FichierPoint d'insertionUsage
__top.inctout au début de la page, avant son premier HTMLen-tête commun : <head>, navigation, ouverture de la mise en page
__bottom.incjuste avant le bloc principalprocédures et fonctions utilitaires partagées

Écrire des méthodes

Le nom d'une procédure ou d'une fonction peut contenir un point. La partie avant le point joue le rôle de classe, et Self désigne l'instance appelante.

procedure TPanier.Ajoute(Quantite, Prix);
Begin
Self.Lignes := Self.Lignes + 1;
Self.Total  := Self.Total + Quantite * Prix;
End;

function TPanier.Resume;
Begin
Result := Self.Lignes + ' article(s) — ' + Self.Total + ' €';
End;

Begin
Object(Panier, TPanier);
Panier.Ajoute(2, 19.90);
EchoChar(Panier.Resume);
End.

Ce n'est pas un vrai système objet : c'est une écriture plus lisible du modèle de clés, résolue à la compilation. Le manuel en détaille la portée et les limites.

La suite

Le manuel du langage couvre la syntaxe complète et les 292 procédures et fonctions de la bibliothèque standard, avec leurs paramètres et leur résultat. Deux sections méritent une lecture même en diagonale : la bibliothèque standard, pour savoir ce qui existe déjà, et les pièges fréquents.