J'ai rencontré à plusieurs reprises un cas où j'ai besoin d'utiliser un fichier/dossier temporaire et de le supprimer ultérieurement.
La solution la plus naturelle consiste alors à suivre les recommandations de "Robust Error Handling and Cleanup in ObjectScript" avec un bloc try/catch/pseudo-finally ou un objet enregistré pour gérer le nettoyage dans le destructeur. %Stream.File* possède également une propriété RemoveOnClose que vous pouvez définir, mais avec précaution, car vous pourriez supprimer accidentellement un fichier important. De plus, cette propriété est réinitialisée par les appels à %Save(), vous devrez donc la remettre à 1 après chaque utilisation.
Il existe cependant un cas particulier : supposons que vous ayez besoin que le fichier temporaire subsiste dans la pile d'exécution. Par exemple :
ClassMethod MethodA()
{
Do ..MethodB(.filename)
}
ClassMethod MethodB(Output filename)
{
Set filename = ##class(%Library.File).TempFilename()
}
Vous pourriez toujours manipuler des objets %Stream.File* avec RemoveOnClose défini sur 1, mais nous nous intéressons ici uniquement aux fichiers temporaires.
C'est là qu'intervient le concept de « Singleton ». IPM propose une implémentation de base dans %IPM.General.Singleton, que vous pouvez étendre pour répondre à différents cas d'utilisation. Le comportement général et le modèle d'utilisation sont les suivants :
- À un niveau de pile supérieur, appelez
%Get() sur cette classe pour obtenir l'unique instance, également accessible par des appels à %Get() à des niveaux de pile inférieurs.
- Lorsque l'objet sort de la portée au niveau de pile le plus élevé qui l'utilise, le code de nettoyage est exécuté.
Cette méthode est plus performante qu'une variable `%` car il n'est pas nécessaire de vérifier sa définition, et elle survit également aux appels NEW sans argument aux niveaux de pile inférieurs grâce à une astuce de manipulation d'objets plus profonde.
Concernant les fichiers temporaires, IPM propose également un singleton pour la gestion des fichiers temporaires. Appliquée à ce problème, la solution est la suivante :
ClassMethod MethodA()
{
Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
Do ..MethodB(.filename)
}
ClassMethod MethodB(Output filename)
{
Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
Set filename = tempFileManager.GetTempFileName(".md")
}