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.
- le bloc principal
Begin…End.; - puis
__top.incs'il existe, puis le HTML de la page et les blocsScript, 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 :
| Fichier | Point d'insertion | Usage |
|---|---|---|
__top.inc | tout au début de la page, avant son premier HTML | en-tête commun : <head>, navigation, ouverture de la mise en page |
__bottom.inc | juste avant le bloc principal | procé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.