Documenter JavaScript avec YUIDoc

La documentation de votre code est un peu comme un test. nous savons tous que nous devrions le faire, nous ne savons pas vraiment comment, et la plupart des gens, si nous sommes honnêtes, ne le font tout simplement pas, mais ceux qui le font en sont un fervent partisan. Ce tutoriel vous permettra de vous familiariser avec l’un des meilleurs moyens de le combattre: YUIDoc.


Qu'est-ce que YUIDoc??

YUIDoc générera une documentation API basée sur les commentaires que vous écrivez.

YUIDoc est une application NodeJS qui générera une documentation sur l'API (sous forme HTML), basée sur les commentaires que vous écrivez dans votre code source JavaScript. En fait, ce n’est pas seulement pour JavaScript: tout langage de programmation prenant en charge les commentaires de bloc délimités par / * * / fonctionne pour YUIDoc. Comme vous pouvez le deviner, YUIDoc est l’un des outils que Yahoo! publie avec sa bibliothèque YUI.

Pour installer YUIDoc, vous devez d'abord installer NodeJS et le gestionnaire de package de nœud (npm). Ensuite, vous pouvez installer YUIDoc via npm -g installe yuidocjs. Vous l'utiliserez en exécutant Yuidoc ; plus sur cela plus tard.


Tout est question de balises

Donc, vous savez que YUIDoc tire sa documentation des commentaires multilignes du fichier source. Bien sûr, vous pourriez avoir des commentaires qui ne font pas partie de la documentation. Pour que YUIDoc reconnaisse un commentaire comme étant significatif, il doit commencer par un double départ: / **. Alors:

 / ** YUIDoc traitera ceci * / / * Mais pas ce * /

Bien sûr, c'est ce qui est à l'intérieur qui compte (à l'intérieur des blocs de commentaires). Chacun doit inclure une et une seule balise principale; il peut également inclure zéro ou plusieurs balises secondaires. Vraiment, YUIDoc est aussi simple que cela: ajoutez des commentaires avec les bonnes balises à votre code et presto: la documentation! Apprenons donc quelques balises. Voici comment nous allons procéder: nous allons passer en revue les balises et leur utilisation, avec des exemples simples d'utilisation; ensuite, nous écrirons et documenterons du code afin que vous ayez une meilleure idée de la manière dont les balises fonctionnent ensemble.


Tags primaires

Avant d'entrer dans les balises principales, rappelez-vous que chaque bloc de commentaires ne peut contenir qu'une seule balise principale. Celles-ci décrivent ce qu'est un morceau de code donné.

@module

le @module tag décrit un groupe de classes liées. (Oui, oui, JavaScript n’a pas de classe: YUIDoc fait référence à des fonctions de constructeur.) Si vous utilisiez YUIDoc pour documenter BackboneJS, le Colonne vertébrale objet serait un module, car il détient le Modèle, Collection, Vue, et d'autres classes. Juste après le tag, vous mettez le nom du module.

 / ** @module Backbone * / var Backbone = Backbone || ;

@classe

le @classe balise décrit correctement une classe unique. Dans la bibliothèque YUI, cela signifie généralement une fonction constructeur, mais si vous préférez utiliser un modèle différent et appeler celui-ci, vous pouvez également le faire. Chaque commentaire avec un @classe la balise devrait aussi avoir un @statique ou @constructeur balise (balises secondaires dont nous parlerons bientôt).

 / ** @class Model * / function Model () 

Si votre classe fait partie d'un module, vous n'avez rien à faire dans le programme. @classe commentaire pour désigner cela: assurez-vous simplement qu'il y a un @module bloc de commentaires en haut de ce fichier.

@méthode

Bien sûr, chaque classe aura au moins quelques méthodes, et vous utiliserez le @méthode tag pour les décrire. Le nom de la méthode suivra la balise et vous utiliserez les balises secondaires @revenir et @param décrire la méthode.

 / ** @method render * / View.prototype.render = fonction (données) 

@propriété

le @propriété tag est utilisé pour marquer les propriétés d'une classe. Vous voudrez utiliser le @type et @défaut balises secondaires avec celui-ci, à coup sûr.

 / ** @property templateString * / this.templateString = "div";

@un événement

Si vous avez des événements personnalisés spéciaux qu'une classe peut déclencher, vous voudrez utiliser le @un événement tag pour les décrire. Voici ce que dit la documentation de YUIDoc:

Un @un événement bloc est un peu similaire à un @méthode bloquer, sauf que @revenir est hors de propos, et @param est utilisé pour décrire les propriétés suspendues de l'objet événement que les rappels écoutant pour l'événement reçoivent.


Tags secondaires

Les blocs de commentaires peuvent avoir plus d'une étiquette secondaire. ils en ont souvent une poignée, et parfois même plus d'un du même type. Regardons quelques-uns de ceux que vous utiliserez souvent.

@ sous-module

Si vous divisez vos modules en sous-modules (peut-être un sous-module par fichier, peut-être pas), la @ sous-module le tag est à votre service.

 / ** @module Util @submodule array * / Util.array = ;

@extends

le @extends tag est utile lorsque vous avez des relations superclasse / sous-classe. Vous pouvez réclamer quelle classe est le parent de la classe actuellement documentée:

 / ** @class AppView @extends Backbone.View * / var AppView = Backbone.View.extend ();

@constructeur

Si une classe peut être instanciée, cela signifie qu’elle a besoin d’une fonction constructeur. Si vous utilisez le modèle de prototype standard en JavaScript, la déclaration de classe est également le constructeur. Cela signifie que vous verrez souvent quelque chose comme ceci:

 / ** @class Recipe @constructor * / function Recipe () 

En fait, vous vous souvenez probablement de moi en disant que chaque @classe la balise doit avoir soit un @constructeur ou @statique balise secondaire.

@statique

En parlant de @statique, C'est ici. Une classe est considérée comme statique lorsque vous ne pouvez pas en créer une instance. Un bon exemple de ceci est la fonction intégrée Math object: vous n'en créez jamais une instance (nouveau Math ()), vous appelez ses méthodes à partir de la classe elle-même.

 / ** @class MathHelpers @static * / var MathHelpers = ;

Une méthode peut aussi être statique: si une classe peut être instanciée, mais a aussi des méthodes au niveau de la classe, ces méthodes sont considérées comme statiques (elles sont appelées sur la classe, pas sur l'instance).

 / ** @class Person @constructor * / function Person ()  / ** @method all @static * / Person.all = function () ;

Dans cet exemple, vous pouvez créer un La personne par exemple, mais le tout la méthode est statique.

@final

Cette balise est utilisée pour des propriétés ou des attributs et marque ladite propriété comme une constante: elle ne doit pas être modifiée. Bien que JavaScript n’ait pas de constantes réelles dans son état actuel, votre modèle de code ou votre guide de style peut les utiliser en principe, ce qui sera utile pour cela..

 / ** @property DATE_FORMAT @final * / var DATE_FORMAT = "% B% d,% Y";

@param

En voici un important: le @param balise est utilisée pour définir les paramètres d'un @méthode (y compris un @constructeur) ou un @un événement. Il y a trois bits d'information qui vont après le @param tag: le nom du paramètre, le type (facultatif) et la description. Ceux-ci peuvent être soit dans l'ordre nom type description ou type nom description; mais dans les deux cas, le type doit être entouré d'accolades.

 / ** @method greet @param person string Nom de la personne à saluer * / function greet (personne) 

Il y a plusieurs façons de personnaliser le prénom partie aussi bien. Le mettre entre crochets le marque comme facultatif, tout en mettant = une certaine valeur après avoir indiqué la valeur par défaut (évidemment, seuls les paramètres facultatifs ont une valeur par défaut). Ensuite, s'il s'agit d'un paramètre fictif pour plusieurs arguments, ajoutez * montrer que. (Évidemment, prénom* est un espace réservé pour 1 ou plusieurs arguments, alors que [prénom]* est un espace réservé pour 0 ou plus).

 / ** @class Template @constructor @param template String Le template chaîne @param [data = ] Object L'objet dont les propriétés seront restituées dans le template * / function Template (template, data) 

@revenir

La plupart de vos méthodes voudront renvoyer une valeur. Il s'agit donc de la balise décrivant cette valeur. N'oubliez pas de lui indiquer le type de la valeur et de lui donner une description..

 / ** @method toHTML @param [template = Recipe.defaultTemplate] Modèle Un objet de modèle @return String Contenu de la recette au format HTML avec le modèle par défaut ou transmis. * / Recipe.prototype.toHTML = fonction (modèle) retourne "peu importe"; ;

@type

Se souvenir du @propriété étiquette primaire? Vous aurez envie de définir le type de ces propriétés, non? Bien, le @type le tag est juste ce dont vous avez besoin. Spécifiez le type après la balise; vous pouvez également proposer plusieurs types en les séparant par des barres verticales:

 / ** @property URL @type String * / URL: "http://net.tutsplus.com", / ** @property person @type String | Person | Object * / this.person = new Person ();

@privé / @protégé

Les langages de programmation traditionnels offrent des propriétés ou méthodes privées: elles ne sont pas accessibles de l'extérieur de l'instance. Tout comme les constantes, JavaScript les a pour pratique, mais vous pouvez utiliser @privé pour les marquer si vous les utilisez. Notez que YUIDoc n’affiche pas les propriétés privées dans les documents qu’il génère (ce qui est logique), cela vous permet donc de documenter une fonctionnalité à votre avantage et de ne pas l’afficher dans les documents..

 / ** @method _toString @private * / var _toString = Object.prototype.toString.call;

Les propriétés et méthodes protégées sont à mi-chemin entre public et privé: elles ne sont accessibles qu'à partir d'instances et d'instances de sous-classes. Si c'est une chose que vous faites en JavaScript, voici votre tag: @protégé.

@a besoin

Si un module dépend d’un ou de plusieurs autres modules, vous pouvez utiliser @a besoin pour marquer cela:

 / ** @module MyFramework.localstorage @ requiert MyFramework * /

Notez que @a besoin pourrait également prendre une liste de dépendances, séparées par des virgules.

@défaut

En déclarant un @propriété, vous pourriez trouver utile de lui donner un @défaut valeur. @défaut doit toujours être utilisé avec @type.

 / ** @property element @type String @default "div" * / element: "div",

@les usages

Comme nous l'avons dit, JavaScript n'a pas vraiment de classes, mais il est suffisamment flexible pour créer l'illusion de classes et même de sous-classes. Ce qui est encore plus cool, c’est qu’il est suffisamment souple pour avoir des mixins ou des modules: c’est là qu’une classe «emprunte» des propriétés ou des méthodes d’une autre classe. Et ce n’est pas non plus un héritage, car vous pouvez mélanger des parties de plusieurs classes (bien sûr, YUI est capable de le faire, mais le Dojo et d’autres bibliothèques le sont aussi). Si vous faites cela, vous trouverez @les usages très utile: il vous permet de déclarer quelles classes une classe donnée mélange dans des parties de.

 / ** @class ModalWindow @uses Window @uses DragDroppable * / var ModalWindow = nouvelle classe (mixes: [Window, DragDroppable],…);

Note: Je viens de composer cette syntaxe mixin, mais je suis sûr d'avoir déjà vu quelque chose de similaire.

@Exemple

Voulez-vous inclure un exemple d'utilisation d'un morceau de code particulier? Utilisez le @Exemple tag, puis écrivez l’exemple ci-dessous en l’indentant d’un niveau. Vous pouvez ajouter autant d'exemples que vous le souhaitez.

 / ** @method greet @example person.greet ("Jane"); * / Person.prototype.greet = fonction (nom) ;

@chainable

Vous connaissez probablement les méthodes chaînables de jQuery. Vous savez où vous pouvez appeler une méthode depuis un appel de méthode, car les méthodes renvoient l'objet? Marquez vos méthodes comme telles avec @chainable.

 / ** @method addClass @chainable * / jQuery.prototype.addClass = function (class) // stuff; retournez ceci; 

@deprecated / @puisque / @bêta

Ces trois balises concernent le support du code (et il peut s'agir de n'importe quel code: module, classe, méthode ou autre). Utilisation @deprecated marquer certaines fonctionnalités comme n'étant plus le meilleur moyen de le faire (les fonctionnalités obsolètes seront probablement supprimées dans une future version du code). Facultativement, vous pouvez inclure un message expliquant en quoi consiste la manière actuelle de le faire..

 / ** @method toJSON @deprecated Passez l'objet à 'JSON.parse' à la place * / Something.toJSON = function () ;

le @puisque La balise indique simplement aux lecteurs quelle version du code donné est ajoutée. Et @bêta marque le code bêta: YUI suggère que @bêta le code pourrait «subir des modifications incompatibles avec les versions antérieures dans un avenir proche».

 / ** @class Tooltip @since 1.2.3 @constructor * / function Tooltip () 

@extension / @extensionfor / extension_pour

le @extension tag (et ses alias) est à peu près le contraire de @les usages. Utilisez-le pour marquer les classes dans lesquelles la classe d'extension peut être mélangée. Bien sûr, sachez que cela ne veut pas dire que ce soit toujours mélangé, mais que ça peut être.

 / ** @class Draggable @extensionfor ModalWindow * /

Commentaires et Markdown

Avant de regarder un exemple concret, laissez-moi souligner deux autres points concernant les blocs de commentaires de la documentation..

Tout d'abord, vous voudrez souvent ajouter un peu plus d'informations sur votre code que ce que les balises offrent. Peut-être voudrez-vous décrire le but des méthodes ou la manière dont une classe s’intègre dans l’ensemble. Ajoutez ces commentaires en haut du bloc de commentaires, au-dessus des balises. YUIDoc les remarquera et les inclura dans la documentation.

 / ** La classe 'Router' est utilisée pour… @class Router @static * / var Router = ;

Deuxièmement, vous serez heureux de savoir que ces commentaires, ainsi que toute description ou tout message écrit après les balises, peuvent être écrits dans Markdown et que YUIDoc le convertira en HTML correct. Vous pouvez même mettre en retrait des exemples de blocs de code dans vos commentaires et obtenir la coloration syntaxique.!


Un exemple

Maintenant que vous avez appris les balises, écrivons du code et documentons-le. Créons un le magasin module, qui contient deux classes: Article et Chariot. Chaque Article exemple sera un type d’article dans l’inventaire du magasin: il aura un nom, un prix et une quantité. UNE Chariot instance peut ajouter des articles au panier et calculer le prix total des articles dans le panier (taxe incluse). C'est assez simple, mais nous donne suffisamment de fonctionnalités variées pour utiliser plusieurs des tags dont nous avons parlé. J'ai mis tout le code suivant dans store.js.

Nous commençons par créer le module:

 / ** * Ce module contient des classes pour exécuter un magasin. * @module Store * / var Store = Store || ;

Créons maintenant une "constante": le taux d'imposition.

 / ** * 'TAX_RATE' est stocké sous forme de pourcentage. La valeur est 13. * @property TAX_RATE * @static * @final * @type Number * / Store.TAX_RATE = 13;

C'est une constante (@final) @propriété de @type Nombre. Remarquez que j'ai inclus @statique: c’est parce que, pour une raison quelconque, lorsque nous générons la documentation de ce fichier, YUIDoc l’affichera comme une propriété de notre Article class: il semble que YUIDoc ne supporte pas d'avoir une propriété sur un module. Je suppose que je pourrais créer une classe statique pour tenir cette constante (ainsi que d’autres constantes qui pourraient apparaître si nous développions cela plus avant), mais je l’ai laissé ainsi pour rappel: pour utiliser un outil tel que YUIDoc à son plein potentiel, vous vous devrez peut-être changer votre façon de coder. Vous devrez décider si c'est ce que vous voulez faire.

Maintenant, pour le Article classe:

 / ** * Article @class * @constructor * @ nom_param Chaîne Nom d'article * Prix @param Numéro Prix article * @param quantité Numéro Quantité article (le nombre disponible à l'achat) * / Store.Item = fonction (nom, prix, quantité) / ** * @ nom de propriété * @type Chaîne * / this.name = nom; / ** * @ property property * @type String * / this.price = price * 100; / ** * @property quantité * @type Number * / this.quantity = quantité; / ** * @ iddepropriété * @numéro de type * / this.id = Store.Item._id ++; Store.Item.list [this.id] = this; ;

Comme vous pouvez le constater, ce constructeur a trois paramètres. Ensuite, il y a trois propriétés à l'intérieur du constructeur que nous décrivons également. Puisque nous voulons donner tous les Article un ID unique, nous devons stocker une propriété statique (au niveau de la classe) pour incrémenter l’ID, et une autre propriété statique, un objet qui suit le Articles par leur identifiant.

 / ** * '_id' est incrémenté lorsqu'un nouvel élément est créé, ainsi chaque élément a un ID unique * @ id_propriété * @ numéro de type * @static * @private * / Store.Item._id = 1; / ** * @ property list * @static * @type Object * / Store.Item.list = ;

Que diriez-vous du Chariot classe?

 / ** * @class Cart * @constructor * @ nom_param Chaîne Nom du client * / Store.Cart = fonction (nom) / ** * @ nom_propriété * @type Chaîne * / this.name = nom; / ** * Articles @ propriété * Objet @type * @default  * / this.items = ; ;

Il n’ya vraiment rien de nouveau ici: notez que nous déclarons que l’état par défaut (ou initial) de la articles la propriété est un objet vide.

Maintenant, les méthodes. Pour le ajouter un item, un des paramètres est optionnel, donc nous le déclarons comme tel et lui donnons une valeur par défaut de 1. Nous notons également que nous faisons la méthode @chainable.

 / ** * Ajoute au panier un ou plusieurs articles donnés, si la quantité choisie * est disponible. Sinon, aucun n'est ajouté. * * @method addItem * @param item Object Un objet 'Item' * @param [quantité = 1] Number Nombre d'éléments à ajouter au panier * @chainable * / Store.Cart.prototype.addItem = fonction (article, quantité) quantité = quantité || 1; if (item.quantity> = quantité) this.items [item.id] = this.items [item.id] || 0; this.items [item.id] + = quantité; item.quantity - = quantité;  retourne ceci; ;

Enfin, nous voulons pouvoir renvoyer le prix total, taxes comprises. Notez que nous faisons le calcul du prix en cents, puis nous convertissons en dollars et arrondissons à deux décimales..

 / ** * @method total * @return Number valeur totale incluse dans le contenu du panier * / Store.Cart.prototype.total = function () var subtotal, id; sous-total = 0; for (id dans this.items) if (this.items.hasOwnProperty (id)) sous-total + = Store.Item.list [id] .price * this.items [id];  retourne parseFloat (((sous-total * (1 + Store.TAX_RATE / 100)) / 100) .toFixed (2)); ;

Si vous voulez tester ce code, voici quelques tests simples:

 var pomme, poire, livre, bureau, assertÉquals; assertEquals = function (un, deux, msg) console.log (((un === deux)?? "PASS:": "FAIL:") + msg); ; apple = new Store.Item ('Granny Smith Apple', 1.00, 5); pear = new Store.Item ('Barlett Pear', 2,00, 3); book = new Store.Item ('On Writing Well', 15.99, 2); desk = new Store.Item ('IKEA Gallant', 123.45, 1); cart = new Store.Cart ('Andrew'); cart.addItem (apple, 1) .addItem (livre, 3) .addItem (bureau, 1); assertEquals (apple.quantity, 4, "ajouter 1 pomme supprime 1 de la quantité de l'article"); assertEquals (book.quantity, 2, "essayer d'ajouter plus de livres qu'il n'y a de moyens, aucun n'est ajouté"); assertEquals (cart.total (), 140,63, "le prix total pour 1 pomme et 1 pupitre est de 140,63");

Génération de la documentation

Maintenant que nous avons écrit le code et les blocs de commentaires, il est temps de générer la documentation..

Si vous l'avez installé globalement via NPM, vous pourrez simplement exécuter yuidoc chemin vers js. Dans mon cas, c'est

 Yuidoc .

Maintenant, vous verrez que vous avez un en dehors répertoire dans ce dossier; ouvrir out / index.html, et vous verrez la documentation. Voici quelle partie de la Chariot la documentation de classe ressemblera à:


Configuration de la sortie

Vous pouvez définir plusieurs options de configuration lors de l’utilisation de YUIDoc. Bien sûr, vous pouvez les définir en tant qu'indicateurs de ligne de commande, mais je préférerais les définir dans un fichier de configuration JSON. Dans votre répertoire de projet, créez un fichier nommé yuidoc.json. Premièrement, il y a une foule d'informations générales sur le projet que vous pouvez définir; cela n'affecte pas trop la sortie, mais il est bon de les documenter:

 "name": "Documentation de JavaScript avec YUIDoc", "description": "Un tutoriel sur YUIDoc, pour Nettuts +", "version": "1.0.0", "url": "http://net.tutsplus.com "

Ensuite, vous pouvez définir un certain nombre d’options réelles. En voici quelques intéressantes.

  • linkNatives: définissez ceci sur «true» pour lier les types natifs tels que String ou Number aux documents MDN.
  • surpasser: utilisez celui-ci pour renommer le en dehors annuaire
  • les chemins: utilisez ceci pour définir quels chemins YUIDoc cherche les fichiers JavaScript.
  • exclure: définissez ceci sur une liste de fichiers séparés par des virgules que vous souhaitez que YUIDoc ignore.

Tant que vous définissez le les chemins options, vous pouvez exécuter yuidoc -c yuidoc.json et YUIDoc sera exécuté. Même si vous ne définissez pas les chemins et juste courir Yuidoc ., YUIDoc verra ce fichier de configuration et l'appliquera.

Voici mon fichier de configuration total pour ce projet:

 "name": "Documentation de JavaScript avec YUIDoc", "description": "Un tutoriel sur YUIDoc, pour Nettuts +", "version": "1.0.0", "url": "http://net.tutsplus.com "," options ": " linkNatives ":" true "," relais ":" ./docs "," chemins ":". " 

Évaluation

Sur la base des balises proposées par YUIDoc, vous pouvez voir qu'il a été conçu pour JavaScript écrit dans un style POO traditionnel, ainsi que spécialement pour les widgets YUI et autres (en fait, j'ai omis plusieurs balises spécifiques à YUI). À cause de tout cela, vous constaterez peut-être que plusieurs balises ne vous sont pas utiles. Ensuite, vous devez vous demander si vous êtes prêt à modifier votre style de codage pour mieux correspondre à la façon de penser de YUIDoc. Mais même si vous n'allez pas changer, je pense que vous constaterez que la plupart des balises YUIDoc conviendront. tout va bien.

La plus grande question à moi est de savoir si vous aimez avoir votre documentation en ligne avec votre code.

Le code d'exemple que nous avons écrit ci-dessus est de 120 lignes avec des commentaires, 40 lignes sans. De toute évidence, il s’agit d’un code super simple et pratiquement tous les exemples du monde réel seraient plus équilibrés; Cependant, la lecture de ce code intercalé pourrait être difficile. Personnellement, je pense que je vais faire un procès équitable à YUIDoc: je vais documenter mon code JavaScript au fur et à mesure que je l'écris (ou du moins, parallèlement) au cours des prochaines semaines. Je serais intéressé de voir si ou comment cela affecte mon style de codage et mon flux de travail.

Vous connaissez la routine: aimez-la ou détestez-la, laissez-moi savoir dans les commentaires!


Pour plus

  • Publication du blog de YUIDoc 0.3.0
  • YUIDoc Page d'accueil
  • Utiliser YUIDoc
  • Référence de syntaxe YUIDoc
  • Thèmes YUIDoc