IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Découvrez les flux de syndication Delphi
(RSS, ATOM) et comment les utiliser

Le , par Nothus

0PARTAGES

Lorsque votre projet web prend de l'ampleur et, comme l'auteur de cette article, les frameworks ne sont pas toujours votre ami (pour diverses raisons, à commencer la lourdeur qu'apporte parfois inutilement ces outils), vous vous confrontez à la difficultés de tenir votre code documenté à jour.

Pire, il s'agit d'un parcours du combattant lorsque l'on reprend ses scripts et que des fonctions ont été ajoutées - mais que le petit mot d'accompagnement s'est oublié en route... C'est ainsi que souvent, il est indiqué comme référence (car ça en est une) la notation suivante :
Code javascript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
/** 
 * Crée une instance de Cercle 
 *  
 * @constructor 
 * @this {Cercle} 
 * @param {number} r Le rayon désiré du cercle. 
 */ 
function Cercle(r) { 
    /** @private */ this.rayon = r; 
    /** @private */ this.circonference = 2 * Math.PI * r; 
};

C'est sympa, mais en condition utilisateur - c'est-à-dire sur le poste du client - son accès dynamique est la croix et la bannière. Parce que la doc n'est pas dans la fonction, quelle est sous la forme d'un commentaire - ce que les fonctionnalités natives de Javascript ne considèrent que peu. Sur ce sujet, Python a (comme toujours !) une solution élégante :

Code python : Sélectionner tout
1
2
3
4
5
def maFonction():  
    """La doc de ma fonction qui dit toujours 'oui'... """  
    return True  
  
print(maFonction.__doc__)

C'est une propriété... magique ! Et pratique pour les IDLE, qui s'appuie sur ces déclarations, ou la génération automatique, y compris en cours d'exécution du script. Vous pouvez également respecter précisément les conventions d'écriture pour y ajouter la liste de vos paramètres, retours, etc.

Pour Javascript, ça se complique (comme toujours !). Pour ma part, j'ai développé une petite fonction bien sympathique, sans grand mérite (elle ne s'appuie que sur ce qui existe déjà), mais qui peut se révéler pratique à l'usage quotidien.

Tout d'abord cette solution passe par les méthodes héritées de l'objet 'Function' - car en Javascript, chaque fonction est un objet Function qui hérite de ses propriétés.

Plus particulièrement de 'Function.prototype' qui en représente les méthodes et propriétés parentes qui nous intéressent. Si le MDN indique qu'il n'est pas possible d'éditer ces méthodes, la pratique semble le permettre (ou alors j'ai une série de navigateurs qui souhaitent ma mort...). Ainsi dans la console JS de Firefox :

Code javascript : Sélectionner tout
1
2
3
4
5
6
7
>> Function.prototype.toString() 
"function () { 
}" 
>> Function.prototype.toString = 3 
3 
>> Function.prototype.toString() 
TypeError: Function.prototype.toString is not a function

Dans l'absolu, le recours à 'Function.prototype' pour mon exemple n'est pas obligatoire, une simple fonction avec en argument l'objet fonction et un éventuel parseur, mais permet de sérialiser au mieux la documentation pour ses fonctions.

Retour à nos moutons : 'Function.prototype.toString' permet d'obtenir le "code source" de la fonction, c'est-à-dire le texte déclaré pour la fonction. Dès lors, une simple expression régulière qui recherchera une sous-chaîne bien particulière, permettra de récupérer la doc qui est contenue. Cela fonctionne pour les trois principales déclarations de fonction, que je liste en exemple plus bas. Le cœur de la fonction se résume ainsi :

Code javascript : Sélectionner tout
1
2
>> (function() { ":doc: Super !"; }).toString().match(/":doc:([^\"]+)"/)[1];  
" Super !"

... Soit respectivement :
(1) créer une fonction anonyme, contenant ici seulement de la doc (variable intermédiaire) ;
(2) on récupère la source en texte ;
(3) on récupère par une expression régulière, ce qui nous intéresse. Éventuellement soit pour une récupération brute, soit pour un traitement. Voire, cas ultime, une modification de la fonction qui sera exécuté par 'eval' (ajout de paramètres, etc - ce qui est possible mais non-souhaitable, la solution idéale reste de créer une fonction conteneur, sur le principe des décorateurs Pythoniques).

Voici la portion complète d'un exemple de ce que je mets en oeuvre, dont l'expression régulière a été volontairement simplifiée et sans boucles, grâce au drapeau "groupe" de la méthode 'match' :

Code javascript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<html>  
<head> 
    <meta charset="utf-8">  
    <title>Documentation JS</title> 
  
</head> 
<body> 
  
    <script type="text/javascript">  
        try {  
            Function.prototype.documenter();  
        } catch(e) {  
            Function.prototype.documenter = function() {  
                r = {};  
                try { 
                    txt = this.toString();  
                } catch(e) {  
                    return false;  
                }  
                r.nom = this.name;  
                r.script = txt;  
                tmp = txt.match(/":doc:([^\"]+)"/);  
                if (tmp!=null) {  
                    tmp = tmp[1].replace(  
                        /\\\n(\t*)/g,  
                        function(...args) {  
                            return " ";  
                        } 
                    ).replace( 
                        /\\n|\\t|\t/g,  
                        function(trouve,...args) {  
                            console.log(trouve);  
                            switch(trouve) {  
                                case "\\n":  
                                    return "<br />";  
                                case "\t":  
                                    return " ";  
                                case "\\t":  
                                    return " ";  
                            }  
                        } 
                    );  
                }  
                r.aide = (tmp!="")?tmp:null;  
                return r;  
            };  
        } 
  
        function Test1 () { 
            ":doc:\ 
            Ceci est une document pour la fonction n°1.\ 
            Sur plusieurs lignes dans le code,\n mais aussi dans le texte affiché. Et même des espaces all-\tongé !";  
        } 
        Test2 = function () {  
            ":doc: Documentation pour la fonction 2.";  
        }  
        Test3 = () => {  
            ":doc:";  
        }  
        Test4 = () => {}  
  
        console.log(Test1.documenter());  
  
        console.log(Test2.documenter());  
  
        console.log(Test3.documenter());  
  
        console.log(Test4.documenter());  
  
    </script> 
</body> 
</html>

Il est possible de pousser plus loin, en ajoutant du BB code (type Markdown) qui sera traduit et de conventionner la présentation. En attendant, un petit projet, doubler d'une boucle récursive, permet déjà de dresser une doc correcte en quelques lignes de code, directement depuis un poste client qui exécute le script en cours

Bonne journée à tous ! Et bon code...

Une erreur dans cette actualité ? Signalez-nous-la !