DEV Community

Cover image for Nietzsche reencarnado num gato, uma "ferramente" CLI feita com GO
ionnss
ionnss

Posted on • Edited on

Nietzsche reencarnado num gato, uma "ferramente" CLI feita com GO

Image description

Estou com três projetos de GO em mente, mas com medo de terminá-los. Quero fazer e ter a sensação de que estou aprendendo no processo, ao invés de só copiar e colar códigos de stackoverflow e chatgpt.

Eu quero dissecar os códigos, os conceitos e as ideias dos projetos para explicar em algum artigo, tipo esse. Acredito que assim eu conseguiria absorver bem o conhecimento por trás da produção dos códigos dos projetos.

Dos três projetos, nenhum se mostra ser algo muito simples. Então pensei em construir um quarto projeto, mais simples, mais curto e que eu consiga aprender alguma coisa.

Alguma coisa é melhor do que nada. E nada é melhor do que qualquer coisa inacabada.

Mas enfim, vamos nessa!

FCAT?

Ah, o nome é zuado mesmo, mas pensei no conceito de f-string, onde você introduz uma string em algum código.

Quanto ao gato... bem, aí você me pegou. As pessoas gostam de gatos. Somado a isso pensei que Nietzsche seria um gato, ao invés de um cachorro, uma borboleta, um elefante, um dinossauro ou um bicho preguiça. Então é isso. É gato, porque SIM.

Qual é o problema?

Começamos com o fato de já termos um arquivo txt com as citações do Nitzsche. O programa precisa selecionar alguma destas, de maneira aleatória e disponibilizar ao usuário. Além disso, precisa imprimir o gato em ASCII e formar um balão de diálogo em volta do quote exibido.

Resumindo:

Arquivo com as citações: arquivo .txt com citações do Nietzsche, onde cada citação esteja em uma linha separada.

Desenho de gato em ASCII: Vamos definir o desenho do gato que será impresso no terminal.

Gostei desse. Tem olhos hipnotizantes.

 ,_     _
 |\\_,-~/
 / _  _ |    ,--.
(  @  @ )   / ,-'
 \  _T_/-._( (
 /         `. \
|         _  \ |
 \ \ ,  /      |
  || |-_\__   /
 ((_/`(____,-'

Enter fullscreen mode Exit fullscreen mode

Carregar e selecionar uma citação aleatória: O programa vai ler as citações de um arquivo .txt e selecionar uma aleatoriamente.

Imprimir a citação com o balão de diálogo: A citação será exibida dentro de um balão de diálogo acima do gato.

Letes go, bebê

Antes de mais nada:

Crie um diretório para o projeto e navegue até ele:

mkdir fcat
cd fcat
Enter fullscreen mode Exit fullscreen mode

Crie um arquivo main.go:

touch main.go
Enter fullscreen mode Exit fullscreen mode

Inicialize os módulos do go:

go mod init main.go
Enter fullscreen mode Exit fullscreen mode

Seu diretório deverá estar tipo assim:

fcat
.
├── go.mod
├── main.go
└── quotes.txt
Enter fullscreen mode Exit fullscreen mode

Agora abra o main.go em sua IDE de preferência.

NVIM se for do hype XD

Explicação do código:

Função carregarCitations

Essa função abre o arquivo de citações (nietzsche.txt), lê cada linha, e armazena todas as citações em uma lista.

A função não irá receber argumentos, apenas retornará uma lista/slice de strings e erro: string e error:

package main

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

func carregarCitations()([]string, error) {
}
Enter fullscreen mode Exit fullscreen mode

Dentro da função iremos inicializar um slice/lista para receber todas as citações:

package main

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

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

}
Enter fullscreen mode Exit fullscreen mode

Agora, vamos abrir o arquivo txt:

package main

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

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   
}
Enter fullscreen mode Exit fullscreen mode

Agora, nós vamos precisar criar um "scanner" para realizar a leitura do nosso arquivo de citações quotes.txt.

Ele também precisara ler cada linha do arquivo.

package main

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

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)


    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista/slice citas
    }
}

Enter fullscreen mode Exit fullscreen mode

Agora, faremos a verificação do erro na leitura do arquivo txt de citações e o retorno da nossa lista com as citações que foram adicionadas à mesma.

package main

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

func carregarCitations([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista citas
    }

    // Verifica se houve erro na leitura do arq txt
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    // Retornar nossa lista com citações
    return citas, nil // Retorna lista de citações
}
Enter fullscreen mode Exit fullscreen mode

Agora precisamos criar a função main para retornar as citações e verificar se a função carregarCitations está correta:

func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações", err)
        return
    }

    for _, citation := range citations {
        fmt.Println(citation)
    }
}
Enter fullscreen mode Exit fullscreen mode

O código deve estar assim:

package main

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

func carregarCitations([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista citas
    }

    // Verifica se houve erro na leitura do arq txt
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    // Retornar nossa lista com citações
    return citas, nil // Retorna lista de citações
}

func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações", err)
        return
    }

    for _, citation := range citations {
        fmt.Println(citation)
    }
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos executar o código no terminal

go run main.go
Enter fullscreen mode Exit fullscreen mode

Você deve visualizar todas as citações do seu arquivo quotes.txt em seu terminal.

Função getRandomCitation

Essa função usa a biblioteca math/rand para selecionar uma citação aleatória da lista.

Dentro dos parênteses da função (), você define os parâmetros que a função recebe como entrada. No exemplo:

  • citations []string significa que a função getRandomCitation espera um argumento chamado citations, que é um slice de strings (ou seja, uma lista de strings).
func getRandomCitation(citations []string

Enter fullscreen mode Exit fullscreen mode
  • []string é a sintaxe de Go para dizer "uma fatia de strings", ou seja, uma coleção ordenada de strings.

Quando você chama a função, você deve passar uma lista de citações (por exemplo, carregada do arquivo quotes.txt), e essa lista será usada dentro da função.

Após os parênteses de entrada, logo antes do corpo da função {}, você especifica o tipo de valor que a função vai retornar.

  • string logo após os parênteses significa que a função vai retornar uma string quando terminar de executar.
func getRandomCitation(citations []string) string {

Enter fullscreen mode Exit fullscreen mode

Neste caso, a função vai retornar uma citação aleatória, que é uma única string.

Entretanto, precisamos gerar um valor aleatório, mas REALMENTE aleatório. Se utilizarmos somente rand.Seed(), a semente padrão será sempre a mesma. Por isso precisamos passar como parâmetros, outras duas funções:

  • time.Now(), que retorna o horário atual

  • UnixNano(), que converterá esse horário em um número inteiro, representando a quantidade de nanosegundos desde 1 de janeiro de 1970. A alta granularidade que é o pulo do gato XD

E depois precisamos que a função retorne um índice aleatório de citations de acordo com o tamanho da lista de citações (length)

import (
    "math/rand" // Não esqueça de incluir essa biblioteca
    "time"      // Não esqueça de incluir essa biblioteca
)

func getRandomCitation(citations []string) string {

    // Inicializa um número aleatório
    rand.Seed(time.Now().UnixNano())

    // Seleciona um índice aleatório de citations
    randomIndex := rand.Intn(len(citations))

    // Retorna uma citação aleatória
    return cictaions[randomIndex]

}
Enter fullscreen mode Exit fullscreen mode
  • len(citations) retorna o número de citações no slice.

  • rand.Intn(n) gera um número aleatório entre 0 e n-1.

  • rand.Intn(len(citations)) seleciona um índice aleatório válido para acessar uma citação da lista.

E agora vamos alterar a função main, para imprimirmos a citação aleatória:

func main() {
    // Chama função para carregar as citações 
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obtém uma citação aleatória de citations utilizando a função getRandomCitation
    randomCitation := getRandomCitation(citations)

    // Imprime a citação aleatória
    fmt.Println("Citação aleatória", randomCitation)

Enter fullscreen mode Exit fullscreen mode

O nosso código deve estar assim:

package main

import (
    "bufio"
    "fmt"
    "os"
    "math/rand"
    "time"
)

// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
    // Iniciar uma lista para receber todas as citações
    var citas []string

    // Abrir arquivo txt 
    arquivo, err := os.Open("quotes.txt")
    if err != nil {
        return nil, err // Retorna erro se falhar ao abrir o arquivo txt
    }
    defer arquivo.Close() // Garante o fechamento do arquivo ao final

    // Iniciar um scanner para leitura do arquivo
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha do arquivo txt
    for scanner.Scan() {
        linha := scanner.Text()
        citas = append(citas, linha)
    }

    // Verifica se houve algum erro durante a leitura do arquivo
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    return citas, nil // Retorna lista de citações
}

func getRandomCitation(citations []string) string {
    // Inicializa o gerado de numero aleatório
    rand.Seed(time.Now().UnixNano())

    // Seleciona um índice aleatório
    randomIndex := rand.Intn(len(citations))

    // Retornar uma citação aleatório
    return citations[randomIndex]
}

func main() {
    // Chama a função para cerregar citações    
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obtém uma citação aleatória de citations utilizando a função getRandomCitation
    randomCitation := getRandomCitation(citations)

    // Imprime a citação aleatória
    fmt.Println("Citação aleatória:", randomCitation)
}
Enter fullscreen mode Exit fullscreen mode

Agora rode o main.go em seu terminal a fim de verificar se conseguimos uma citação aleatória:

go rum main.go
Enter fullscreen mode Exit fullscreen mode

Função imprimirGato

Essa função exibe o desenho de um gato em ASCII e imprime a citação dentro de um balão de diálogo.

func imprimirGato(citacao string) {
    tamanhoBalao := len(citacao)
    linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
    linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
    linhaCitacao := fmt.Sprintf("| %s |", citacao)
    linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
    linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)

    // Imprime o balão de diálogo
    fmt.Println(linhaTopo)
    fmt.Println(linhaCima)
    fmt.Println(linhaCitacao)
    fmt.Println(linhaBaixo)
    fmt.Println(linhaBase)

    // Imprime o desenho do gato em ASCII com barras escapadas corretamente
    fmt.Println(`        \   
             \  
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/` + "`(____,-'`)")
}

Enter fullscreen mode Exit fullscreen mode

Função main

Na função main(), o programa carrega as citações, seleciona uma aleatória e imprime o gato com a citação em um balão.

func main() {
    // Carregar as citações do arquivo
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obter uma citação aleatória
    randomCitation := getRandomCitation(citations)

    // Imprimir o balão com o gato e a citação aleatória
    imprimirGato(randomCitation)
}


Enter fullscreen mode Exit fullscreen mode

Nosso código final deve estar assim:

package main

import (
    "bufio"
    "fmt"
    "math/rand"
    "os"
    "strings"
    "time"
)

// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
    var citas []string

    arquivo, err := os.Open("quotes.txt")
    if err != nil {
        return nil, err
    }
    defer arquivo.Close()

    scanner := bufio.NewScanner(arquivo)
    for scanner.Scan() {
        linha := scanner.Text()
        citas = append(citas, linha)
    }

    if err := scanner.Err(); err != nil {
        return nil, err
    }

    return citas, nil
}

func getRandomCitation(citations []string) string {
    rand.Seed(time.Now().UnixNano())
    randomIndex := rand.Intn(len(citations))
    return citations[randomIndex]
}

func imprimirGato(citacao string) {
    tamanhoBalao := len(citacao)
    linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
    linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
    linhaCitacao := fmt.Sprintf("| %s |", citacao)
    linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
    linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)

    // Imprime o balão de diálogo
    fmt.Println(linhaTopo)
    fmt.Println(linhaCima)
    fmt.Println(linhaCitacao)
    fmt.Println(linhaBaixo)
    fmt.Println(linhaBase)

    // Imprime o desenho do gato em ASCII com barras escapadas corretamente
    fmt.Println(`        \   
             \  
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/` + "`(____,-'`)")
}

func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    randomCitation := getRandomCitation(citations)
    imprimirGato(randomCitation)
}
Enter fullscreen mode Exit fullscreen mode

Finalizando

Agora nos resta compilar nosso programa e executar.

Compile seu arquivo main.go como fcat:

go build -o fcat main.go
Enter fullscreen mode Exit fullscreen mode

E por fim, execute:

./fcat
Enter fullscreen mode Exit fullscreen mode

O resultado foi esse:

 ------------------------------------------------------
/                                                      \
| He who has a why to live for can bear almost any how |
\                                                      /
 ------------------------------------------------------
        \
             \
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/`(____,-'`)


Enter fullscreen mode Exit fullscreen mode

Achei interessante como algo tão simples pode se tornar tão complicado de executar.

Mas o que me impressionou foi a frase de saída do programa: "He who has a why to live for can bear almost any how"

Que a frase acima lhe inspire a continuar aprendendo.

REPO: https://github.com/ionnss/fcat


ions,

Mais um dia na terra

Top comments (0)