Menu
Coddy logo textTech

Recapitulação - File Parser

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 58 de 107.

challenge icon

Desafio

Fácil

Vamos construir um analisador de arquivos de configuração que reúna todas as técnicas de tratamento de erros deste capítulo. Seu analisador lidará com múltiplos cenários de falha com tipos de erro personalizados, erros sentinela, encapsulamento de erros (error wrapping) e limpeza adequada usando defer.

Você organizará seu código em três arquivos:

  • errors.go: Defina sua infraestrutura de erro para o analisador.

    Crie dois erros sentinela:

    • ErrEmptyContent com a mensagem "file content is empty"
    • ErrInvalidFormat com a mensagem "invalid configuration format"

    Crie um tipo de erro personalizado ParseError com os campos Line (int) e Message (string). Seu método Error() deve retornar: parse error at line [Line]: [Message]

  • parser.go: Construa o analisador de configuração com tratamento de erros em camadas.

    Crie uma struct ConfigParser com um campo booleano parsed para rastrear se a análise foi concluída com sucesso.

    Implemente estes métodos:

    • NewConfigParser() *ConfigParser - cria um novo analisador com parsed definido como false
    • ParseLine(lineNum int, line string) error - valida uma única linha. Se a linha não contiver um caractere =, retorne um *ParseError com o número da linha e a mensagem "missing key-value separator". Caso contrário, retorne nil.
    • Parse(content string) error - o método principal de análise que:
      • Retorna ErrEmptyContent se o conteúdo estiver vazio
      • Retorna ErrInvalidFormat se o conteúdo não contiver pelo menos um caractere de nova linha
      • Divide o conteúdo por novas linhas e chama ParseLine para cada linha (os números das linhas começam em 1)
      • Se ParseLine retornar um erro, envolva-o com "parsing configuration: %w" e retorne
      • Define parsed como true em caso de sucesso e retorna nil
    • Status() string - retorna "ready" se parsed for true, caso contrário, retorna "not parsed"
  • main.go: Leia o conteúdo da configuração e demonstre uma inspeção de erros abrangente.

    Leia duas linhas de entrada que juntas formam o conteúdo da configuração (junte-as com uma nova linha). Use defer para sempre imprimir o status do analisador ao final, independentemente do sucesso ou falha.

    Após tentar analisar, inspecione qualquer erro usando tanto errors.Is() quanto errors.As() para fornecer um feedback específico baseado no que deu errado.

As seguintes entradas serão fornecidas:

  • Linha 1: Primeira linha do conteúdo da configuração
  • Linha 2: Segunda linha do conteúdo da configuração

Trate os erros com mensagens específicas:

  • Se errors.Is() encontrar ErrEmptyContent: imprima Error: No configuration provided
  • Se errors.Is() encontrar ErrInvalidFormat: imprima Error: Configuration must have multiple lines
  • Se errors.As() encontrar um *ParseError: imprima o erro completo encapsulado e, em uma nova linha, imprima Fix line [Line]: [Message]
  • Se a análise for bem-sucedida: imprima Configuration parsed successfully

Após tratar o resultado (sucesso ou erro), o status adiado (deferred) deve ser impresso em uma nova linha: Parser status: [status]

Por exemplo, dados host=localhost e port=8080, sua saída deve ser:

Configuration parsed successfully
Parser status: ready

E dados host=localhost e invalid line, sua saída deve ser:

parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsed

Experimente você mesmo

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Ler a primeira linha da configuração
	line1, _ := reader.ReadString('\n')
	line1 = line1[:len(line1)-1] // Remover a quebra de linha final
	
	// Ler a segunda linha da configuração
	line2, _ := reader.ReadString('\n')
	if len(line2) > 0 && line2[len(line2)-1] == '\n' {
		line2 = line2[:len(line2)-1]
	}
	
	// Juntar as duas linhas com uma quebra de linha para formar o conteúdo da configuração
	content := line1 + "\n" + line2
	
	// Criar um novo parser
	parser := NewConfigParser()
	
	// TODO: Usar defer para sempre imprimir o status do parser ao final
	// Formato: "Parser status: [status]"
	
	// TODO: Tentar analisar o conteúdo
	
	// TODO: Tratar erros usando errors.Is() e errors.As()
	// - Se errors.Is() encontrar ErrEmptyContent: imprimir "Error: No configuration provided"
	// - Se errors.Is() encontrar ErrInvalidFormat: imprimir "Error: Configuration must have multiple lines"
	// - Se errors.As() encontrar um *ParseError: imprimir o erro completo envolvido,
	//   então em uma nova linha imprimir "Fix line [Line]: [Message]"
	// - Se a análise for bem-sucedida: imprimir "Configuration parsed successfully"
	
	_ = errors.Is // dica: use errors.Is para erros sentinela
	_ = errors.As // dica: use errors.As para tipos de erro personalizados
	_ = fmt.Println
}

Todas as lições de Programação Orientada a Objetos