Pular para o conteúdo

Entrada: teclado, cano e arquivo

Perguntar quando há alguém do outro lado — e ler do stdin quando não há.

Uma ferramenta de terminal recebe dado de três lugares, e confundi-los é o que faz um programa travar dentro de um script: o teclado, o cano (cat x | prog) e o arquivo passado como argumento.

dataforge
adopt Arcane.OS as OS
adopt Arcane.Cli as Cli

// A pergunta só faz sentido com alguém do outro lado.
given Cli.tem_terminal():
    out "aqui eu poderia perguntar"
otherwise:
    out "sem terminal: leio do cano, e não pergunto"

Ler o que vier pelo cano#

input() devolve void no fim da entrada, e não levanta: um programa canalizado termina a entrada, e isso não é erro. É o que torna o laço abaixo o idioma da linguagem:

dataforge
linhas := []
persist yes:
    linha := input()
    given linha is void:
        halt
    linhas.append(linha)

out $"{len(linhas)} linha(s) pelo cano"

O padrão que cobre os três casos#

dataforge
adopt Arcane.IO as IO
adopt Arcane.Cli as Cli

action ler_tudo(caminho):
    // Um '-' como caminho quer dizer "a entrada padrão", e é
    // convenção de quase toda ferramenta Unix.
    given caminho is void or caminho is "-":
        pedacos := []
        persist yes:
            linha := input()
            given linha is void:
                halt
            pedacos.append(linha)
        yield join("\n", pedacos)
    yield IO.read(caminho)

// com o arquivo:
adopt Arcane.OS as OS
pasta := $"{OS.temp_dir()}/df-cli-{randint(100000, 999999)}"
IO.mkdir(pasta)
IO.write($"{pasta}/a.txt", "uma linha")
assert ler_tudo($"{pasta}/a.txt") is "uma linha"
IO.remove_tree(pasta)

Perguntar, escolher, confirmar#

dataforge
adopt Arcane.Cli as Cli

// Num terminal, estes três param e esperam. Num script, eles
// precisam de um padrão — senão a automação trava sem dizer por quê.
action nome_do_projeto(args):
    given args["nome"] is not void:
        yield args["nome"]
    given not Cli.tem_terminal():
        trigger "sem terminal: passe --nome"
    yield Cli.perguntar("nome do projeto", "meu-app")

assert nome_do_projeto({"nome": "loja"}) is "loja"

monitor:
    nome_do_projeto({"nome": void})
handle Error as e:
    out e.message

Validar na entrada#

dataforge
adopt Arcane.Cli as Cli

// 'valida' é uma ação que devolve yes/no; a pergunta se repete.
action e_email(texto):
    yield "@" in texto and "." in texto

assert e_email("a@b.co") is yes
assert e_email("nada") is no