Há um padrão com o qual já me deparei várias vezes em que preciso usar um arquivo ou pasta temporária e que ela seja limpa em algum momento mais tarde.
O natural aqui é seguir os padrões de "Robust Error Handling and Cleanup in ObjectScript" , usando um try/catch/pseudo-finally ou um objeto registrado para gerenciar a limpeza no destrutor. %Stream.File* também tem a propriedade RemoveOnClose, que vocês podem ativar… mas usem com cuidado, pois podem acabar excluindo acidentalmente um arquivo importante. Além disso, esse indicador é redefinido ao chamar %Save(), então será necessário configurá-lo novamente como 1 depois disso.
Mas existe um caso complicado: imaginem que vocês precisam que o arquivo temporário sobreviva em um nível superior da pilha. Por exemplo:
ClassMethod MethodA()
{
Do ..MethodB(.filename)
}
ClassMethod MethodB(Output filename)
{
Set filename = ##class(%Library.File).TempFilename()
}
Vocês sempre poderiam passar objetos %Stream.File* com RemoveOnClose definido como 1, mas aqui estamos falando, na verdade, apenas de arquivos temporários.
É aí que entra o conceito de “Singleton”. No IPM , temos uma implementação base em %IPM.General.Singleton que vocês podem estender para cobrir diferentes casos de uso. O comportamento geral e o padrão de uso são:
- Em um nível superior da pilha, vocês chamam
%Get() nessa classe e obtêm a instância única, que também ficará acessível por meio de chamadas a %Get() em níveis inferiores.
- Quando o objeto sai de escopo no nível mais alto da pilha que o utiliza, o código de limpeza é executado.
- Isso é um pouco melhor do que usar uma variável
%, porque vocês não precisam verificar se ela está definida e, além disso, ela sobrevive a NEW sem argumentos nos níveis inferiores da pilha, graças a uma certa “magia” profunda do sistema de objetos.
Passando para os arquivos temporários, o IPM também possui um singleton gerenciador de arquivos temporários . Aplicando isso a este problema, a solução é:
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")
}