DEV Community

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

Posted 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.


ions,

Mais um dia na terra

Top comments (0)