Modules
Un module YScript est simplement un fichier source (.yes) chargé par require, qui construit et
retourne une table rassemblant ses fonctions et valeurs publiques. Cette page documente, côté
auteur d'un module, comment écrire ce fichier : le patron standard, ce que le chunk reçoit au
chargement, où le placer sur le disque, et comment le pré-enregistrer en mémoire sans fichier.
Elle complète stdlib/package.md, qui documente require/package.* côté
consommateur d'un module (recherche de fichier, cache, searchers), et se distingue d'un
module externe, qui package des fonctions C# dans une assembly
séparée plutôt que du code YScript dans un fichier .yes.
Patron standard
Un module est un fichier .yes ordinaire, exécuté comme n'importe quel chunk, à ceci près qu'on
attend de lui qu'il retourne une valeur (typiquement une table) : c'est cette valeur que
require renvoie à l'appelant et met en cache.
-- stack.yes
local M = {}
function M.push(t, v)
t[#t + 1] = v
end
function M.pop(t)
local v = t[#t]
t[#t] = nil
return v
end
return M
-- utilisation
local stack = require("stack")
local t = {}
stack.push(t, 1)
stack.push(t, 2)
print(stack.pop(t)) --> 2
Construire une table locale, y attacher les fonctions publiques du module, puis la return en fin
de fichier : c'est le seul contrat que require impose. Tout le reste (variables locales privées au
module, fonctions internes non exposées via M, etc.) reste un chunk YScript ordinaire.
Ce que reçoit le chunk au chargement
Le fichier du module est chargé et appelé comme une fonction variadique ; require lui passe
exactement deux arguments, récupérables via ... :
- le nom du module tel que passé à
require(ex."stack","yeg.module1") ; - une donnée de chargement associée au searcher qui a trouvé le module — pour un module fichier (searcher « script »), c'est le nom du fichier trouvé sur le disque.
-- stack.yes
local name, filename = ...
-- name == "stack"
-- filename == "/chemin/vers/stack.yes"
local M = {}
...
return M
Un module peut ignorer ces arguments (cas le plus courant) ou s'en servir, par exemple pour du
diagnostic ou pour localiser des fichiers annexes relatifs à filename.
Si le fichier ne retourne aucune valeur (pas de return, ou return sans expression), require
utilise true comme résultat — ce true est ce qui est mis en cache dans package.loaded[nom] et
ce que retournent tous les appels ultérieurs à require pour ce nom. Un module qui n'a besoin
d'aucune valeur exportée (il s'exécute uniquement pour son effet de bord, ex. enregistrer des
métatables globales) peut donc légitimement ne rien retourner.
Emplacement du fichier : ?.yes / ?/init.yes
require("a.b.c") cherche un fichier en substituant le nom (avec ses . convertis en /) dans
chaque gabarit de package.path. Par défaut, chaque racine de recherche fournit deux gabarits :
?.yes— module en un seul fichier :require("stack")→stack.yes;?/init.yes— module en dossier, avec un point d'entréeinit.yes:require("stack")→stack/init.yes.
La forme dossier convient à un module qui se découpe en plusieurs fichiers internes (que init.yes
charge via des require relatifs, des dofile, etc., et rassemble dans la table qu'il retourne),
sans changer le nom sous lequel le module est consommé. Le détail exact du gabarit par défaut
(racines, suffixe de version, variables d'environnement) est documenté dans
stdlib/package.md#packagepath--packagedotnetpath.
package.preload : enregistrer un module sans fichier
Quand un module est déjà construit en mémoire — typiquement déposé par l'application hôte .NET au
démarrage — package.preload permet de l'enregistrer sous un nom, pour qu'un require(nom) côté
script le récupère sans jamais toucher au système de fichiers. Le searcher « preload » est le premier
consulté par require, avant toute recherche par chemin.
Côté auteur/hôte, il suffit de déposer dans package.preload une fonction de chargement portant le
même nom que le module — cette fonction joue exactement le rôle du chunk d'un fichier .yes : elle
reçoit (nom, donnée) et sa valeur de retour est celle que require renverra :
package.preload["stack"] = function(name, data)
local M = {}
function M.push(t, v) t[#t + 1] = v end
function M.pop(t) local v = t[#t]; t[#t] = nil; return v end
return M
end
local stack = require("stack") -- exécute la fonction ci-dessus, sans lire aucun fichier
Voir stdlib/package.md#packagepreload pour le détail de la
table package.preload elle-même.
Cache
Comme tout module, un fichier .yes chargé par require n'est exécuté qu'une seule fois : les
appels suivants avec le même nom retournent la valeur mise en cache — voir
stdlib/package.md#requiremodname pour le détail.