Depuração
Em scripts, nenhuma função é infalível. Mesmo os comandos mais confiáveis podem falhar quando confrontados com entradas ou condições inesperadas. Para nos proteger contra isso, podemos implementar um sistema de depuração personalizado e adotar técnicas de programação defensivas. Ao agrupar funções padrão com mecanismos de tratamento de erros e fornecer feedback informativo, podemos tornar os scripts mais robustos e fáceis de solucionar.
Uma parte importante desta estratégia é usar um sinalizador de depuração global para controlar a saída detalhada, permitindo-nos ativar informações detalhadas de depuração quando necessário, mantendo a saída limpa durante a execução normal.
Sinalizador de depuração global
Um sinalizador de depuração global é uma forma simples, mas eficaz, de controlar o nível de saída de informações durante a execução do script. Quando ativado, ele fornece mensagens de depuração detalhadas que podem ser inestimáveis para acompanhar problemas. Quando desabilitado, mantém a saída concisa para uso em produção.
;; Propósito: Flag global para controlar a saída de depuração.
(define debug #f)Por padrão, a depuração está desativada. Para ativar a saída detalhada durante o desenvolvimento,, basta definir o sinalizador como #t:
;; Propósito: Flag global para controlar a saída de depuração.
(define debug #t)Também podemos ativar ou desativar temporariamente a depuração para seções específicas do código usando funções auxiliares.
Controle de depuração local
Para um controle mais preciso, podemos ativar ou desativar a depuração em partes específicas do script usando funções auxiliares.
;; Propósito: Desativar o modo de depuração para uma seção de código.
(define (debug-off)
(set! debug #f))
;; Propósito: Ativar o modo de depuração para uma seção de código.
(define (debug-on)
(set! debug #t))Isto permite controlar a depuração dinamicamente:
(debug-on) ;; Ativar saída detalhada
;; Alguma lógica de script aqui
(debug-off) ;; Desativar saída detalhadaDepurar sistema de mensagens
Para lidar com eficiência com a saída de depuração no Scheme, usamos uma abordagem estruturada envolvendo várias funções auxiliares. Essas funções garantem que as mensagens de depuração e aviso sejam claras, legíveis e fáceis de manter.
Visão geral do sistema de mensagens de depuração
Nosso sistema de mensagens de depuração consiste nos seguintes componentes:
debug-message– Exibe mensagens de depuração quando a depuração está habilitada.serialize-item– Converte vários tipos de dados do Scheme em uma representação de string.concat– Concatena vários itens em uma única string.list->string– Formata uma lista em uma string legível.message– Exibe a saída no console de mensagens do Lumi.warning-message– Exibe mensagens de aviso quando os avisos estão habilitados.
Cada função desempenha uma função na formatação e exibição de mensagens estruturadas.
Função de mensagem de depuração
A função debug-message é o método principal para exibir a saída de depuração. Ele garante que as mensagens sejam mostradas apenas quando a depuração estiver habilitada.
;; Propósito: Exibir uma mensagem de depuração.
(define (debug-message . items)
(when debug (message "> " (apply concat items))))- A condição
when debuggarante que as mensagens apareçam apenas quando a depuração estiver habilitada. - As mensagens são prefixadas com
"> "para maior clareza. - A função usa
concatpara formatar o conteúdo da mensagem. - Por fim, chama
messagepara enviar a saída para o console de mensagens do Lumi.
Exemplo de uso:
;; Propósito: Retorna a posição na árvore do item ou #f se o item for inválido
(define (get-item-tree-position image item)
(if (item-is-valid? item)
(let ((position (list->item (lumi-image-get-item-position image item))))
(debug-message "item : " (item-get-name item) " has tree position : " position)
position)
#f))Com a depuração habilitada, a saída pode ser:
> item: background-layer has tree position : 3Serializando dados para mensagens de depuração
As mensagens podem conter diferentes tipos de dados, como listas, vetores e números. Para garantir que estejam formatados corretamente, usamos serialize-item.
;; Propósito: Converte vários tipos de dados Scheme (listas, vetores, pares, etc.)
;; em uma representação de string.
(define (serialize-item item)
(cond
((and (list? item) (null? item)) "\"\"") ; Lista vazia
((and (string? item) (string=? item "")) "\"\"") ; String vazia
((list? item) (list->string item)) ; Lista aninhada
((vector? item) ; Trata vetores
(string-append "#("
(string-join (map serialize-item (vector->list item)) " ")
")"))
((pair? item) ; Trata pares
(string-append "("
(serialize-item (car item))
" . "
(serialize-item (cdr item))
")"))
((number? item) (number->string item)) ; Números
((symbol? item) (symbol->string item)) ; Símbolos
((boolean? item) (if item "#t" "#f")) ; Booleanos
((string? item) item) ; Cadeias de caracteres
(else (warning-message "serialize-item: Unsupported item type!" item))))Exemplo de uso:
(serialize-item '(1 2 3))Saída:
list:
1
2
3Concatenação para Mensagens
Para mesclar vários componentes de mensagem em uma única string, usamos concat.
;; Propósito: Concatenar vários itens em uma única string.
(define (concat . items)
(apply string-append (map serialize-item items)))Exemplo de uso:
(concat "Image size: " 1920 "x" 1080)Formatando listas como strings
A função list->string converte uma lista em uma string formatada.
;; Propósito: Converter uma lista de itens em uma string legível.
(define (list->string list)
(if (list? list)
(string-append "list: \n" (string-join (map serialize-item list) "\n"))
(warning-message "list->string: Input is not a list!")))Mensagens de aviso
A função warning-message funciona de forma semelhante a debug-message, mas exibe avisos mesmo quando a depuração está desabilitada.
;; Propósito: Exibir uma mensagem de aviso.
(define (warning-message . items)
(if warning
(message "Warning: " (apply concat items)))
#f)- Garante que as mensagens sejam mostradas apenas quando os avisos estão habilitados (o sinalizador
warningé definido emcommon.scmcomo#t). - Chama
concatpara formatar o conteúdo da mensagem. - Usa
messagepara enviar saída para Lumi.
Aprimorando funções padrão
Uma vez implementado um sistema de depuração, podemos aprimorar a biblioteca de funções incorporando mensagens detalhadas. Isso fornece informações sobre estados de itens, valores de variáveis e chamadas de função.
Um exemplo comum é item-is-valid?, que envolve lumi-item-id-is-valid para retornar #t ou #f. Se #f for retornado, podemos acionar um warning-message no código de chamada, se a entrada não for um número podemos dar um aviso na função.
;; Propósito: Verificar se um item é válido, retorna #t ou #f.
;; Emite um aviso se o item não for um número.
(define (item-is-valid? item)
(if (number? item)
(= (list->item (lumi-item-id-is-valid item)) 1)
(begin
(warning-message "item-is-valid?: Expected a number, but received: " item)
#f)))Uso prático
Ao desenvolver plug-ins do Scheme, agrupar funções dessa forma reduz significativamente o tempo de depuração e garante um código robusto e de fácil manutenção. Com o sistema de depuração de depuração instalado, podemos gerar um fluxo de depuração estruturado no console de erros com o toque de um botão.
Neste fluxo de depuração, as chamadas de função são marcadas com um asterisco (*), facilitando o rastreamento da execução de scripts e a identificação de falhas, especialmente em plug-ins complexos. Essa visibilidade nos ajuda a entender o fluxo das operações e a diagnosticar comportamentos inesperados com eficiência.
Um wrapper para a função de mensagem usar um *
(define (call . items)
(when debug (message "* (" (apply concat items) ")")))Exemplo de call sendo usado na prática:
;; Propósito: Aplica o processo de texturização à lista fornecida de máscaras de grupo
(define (process-masks groups pattern) (call 'process-masks)
(for-each
(lambda (group)
(let ((mask (add-mask-to-layer group ADD-MASK-WHITE)))
(message "Process mask : " (item-get-name group))
(fill-and-adjust-group-mask group mask pattern)
(lumi-layer-set-opacity group (get 'color-opacity))
(lumi-item-set-expanded (item-get-parent group) 0)
(lumi-selection-none (get-image))))
(ensure-list groups)))Exemplo de um fluxo de depuração conforme um plug-in é executado:
> Recording the plug-in settings
* (convert-gui-settings)
> all-masks : 1
> strokes : 1
> color : 1
> plate-layer : 1
> drawables : #(37)
* (filter-list-for-matching-groups)
> all-masks : #t
> sub-groups of group : root
blue
blue_strokes
blue_colour
yellow
yellow_strokes
yellow_colour
gray
gray_strokes
gray_colour
> groups with identifier in name: _colour
blue_colour
yellow_colour
gray_colour
* (filter-list-for-matching-groups)
> all-masks : #t
> sub-groups of group : root
blue
blue_strokes
blue_colour
yellow
yellow_strokes
yellow_colour
gray
gray_strokes
gray_colour
> groups with identifier in name: _strokes
blue_strokes
yellow_strokes
gray_strokes
* (begin-apply-texture)
Start Apply Texture
> color : #t
Texturing color group masks
> color-pattern : 2655
* (process-masks)
Process mask : blue_colour
* (fill-and-adjust-group-mask)
> Fill-and-adjust : blue_colour mask
> using pattern for fill : 2655
* (apply-color-effect)
> color-contrast : 64
> color-levels-gamma : 10
> levels on drawable: blue_colour mask
> gamma: 8.2
> low-in: 0.7278 high-in: 0.9222
> low-out: 0 high-out: 1
> light-opacity : 6
> light-opacity : 6
* (apply-light-effect)
> apply-light-effect opacity : 6
> from layer : light_blue
> edit-copy light_blue
> edit-paste blue_colour mask
> shade-opacity : 60
> shade-opacity : 60
* (apply-light-effect)
> apply-light-effect opacity : 60
> from layer : shad_blue_opa*5
> edit-copy shad_blue_opa*5
> edit-paste blue_colour mask
* (apply-opaque-effect)
> children in : blue_colour
blue_colour
hue_blue
light_blue
shad_blue_opa*5
base_blue
...
...
...
Finished Apply Texture!Esse log estruturado fornece um cronograma claro de chamadas de função e alterações de dados, facilitando significativamente a depuração e a análise de desempenho.
Conclusão
Ao implementar um sistema de depuração estruturado, criamos scripts mais seguros e de fácil manutenção que oferecem insights em tempo real sobre a execução.
Principais conclusões
- Controlar verbosidade – Use um sinalizador de depuração global para gerir os níveis de saída.
- Forneça feedback claro – Envolva funções padrão com mensagens informativas de depuração.
- Aumente a robustez – Lide com entradas inesperadas com elegância para evitar erros.
- Simplifique a solução de problemas – Mensagens de depuração estruturadas facilitam o diagnóstico e a correção de problemas.
Com essa abordagem, os scripts “explicam-se” efetivamente à medida que processam dados, reduzindo a frustração e melhorando a eficiência do fluxo de trabalho. A depuração se torna uma ferramenta proativa em vez de uma tarefa reativa, tornando o processo de scripting de script mais suave e gratificante.