Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
4 changed files with 38 additions and 22 deletions
Showing only changes of commit 5b2bb7e681 - Show all commits
+3 -3
View File
@@ -441,14 +441,14 @@ import (
"github.com/larvit/fejkdata/data"
)
//go:embed *.json *.tsv
//go:embed *.json
var mydata embed.FS
func main() { os.Exit(cli.Main(append(data.Modules(), mydata)...)) }
```
It takes `fejkdata`'s flags and exit codes, and names itself by the file it runs from in
its help and errors. `--no-shipped-data` leaves out the modules passed to `Main`, and
Add `*.tsv` to the embed where your data holds a table. The CLI takes `fejkdata`'s flags
and exit codes, and names itself by the file it runs from in its help and errors. `--no-shipped-data` leaves out the modules passed to `Main`, and
`--version` prints your module's version beside the fejkdata version it is built with.
`fejkdata`'s own `main` is `os.Exit(cli.Main(data.Modules()...))`.
+30 -18
View File
@@ -22,16 +22,16 @@ import (
"github.com/larvit/fejkdata"
)
const usage = `Usage: <template> | fejkdata [flags]
fejkdata --list | --help | --version
const usage = `Usage: <template> | COMMAND [flags]
COMMAND --list | --help | --version
fejkdata reads one template from stdin and renders it:
COMMAND reads one template from stdin and renders it:
echo 'name: {/sv_SE.person.last}' | fejkdata
echo '{"format":"{x}","x":["bosse","lina"]}' | fejkdata
fejkdata < template.txt
echo 'name: {/sv_SE.person.last}' | COMMAND
echo '{"format":"{x}","x":["bosse","lina"]}' | COMMAND
COMMAND < template.txt
fejkdata <<'EOF'
COMMAND <<'EOF'
born {date(1990-01-01,2010-12-31,'2006-01-02')}
EOF
@@ -42,7 +42,7 @@ path into one ({/sv_SE.person.last}), a table's row by key or name
({/misc.territory[SE]}), and .. steps up from a row to the row it links to
({/geo.SE.locality..municipality.name}).
Under --format text, the default, what you send is what renders, and fejkdata adds
Under --format text, the default, what you send is what renders, and COMMAND adds
nothing: a format string keeps every byte, so echo's newline ends each render, and
printf '%s' sends none. -n joins renders with --separator, empty by default. A JSON
object, array or string drops the whitespace around it, and null alone renders nothing;
@@ -569,7 +569,13 @@ func Main(modules ...fs.FS) int {
if fi, err := os.Stdin.Stat(); err == nil && fi.Mode()&os.ModeCharDevice != 0 {
stdin = nil
}
name := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
name := filepath.Base(os.Args[0])
if ext := filepath.Ext(name); strings.EqualFold(ext, ".exe") {
name = strings.TrimSuffix(name, ext)
}
if name == "." || name == "" {
name = "fejkdata"
}
return run(name, modules, os.Args[1:], stdin, os.Stdout, os.Stderr)
}
@@ -581,7 +587,7 @@ func run(name string, modules []fs.FS, args []string, stdin io.Reader, stdout, s
return misuse(stderr, name, err)
}
if in.help {
io.WriteString(stdout, strings.ReplaceAll(usage, "fejkdata", name))
io.WriteString(stdout, strings.ReplaceAll(usage, "COMMAND", name))
return 0
}
if in.version {
@@ -600,8 +606,7 @@ func run(name string, modules []fs.FS, args []string, stdin io.Reader, stdout, s
}
f, err := fejkdata.New(in.options(modules)...)
if err != nil {
fmt.Fprintln(stderr, err)
return 1
return fail(stderr, name, err)
}
if in.list {
for _, p := range f.List() {
@@ -639,7 +644,7 @@ func fail(stderr io.Writer, name string, err error) int {
if errors.As(err, &te) {
return misuse(stderr, name, te.error)
}
fmt.Fprintln(stderr, err)
report(stderr, name, err)
if errors.Is(err, fejkdata.ErrNoColumns) {
fmt.Fprintln(stderr, "wrap that JSON in single quotes, which keep a shell from expanding its braces")
}
@@ -647,11 +652,16 @@ func fail(stderr io.Writer, name string, err error) int {
}
func misuse(stderr io.Writer, name string, err error) int {
// A library error opens with the library's name, so the prefix is not doubled.
fmt.Fprintf(stderr, "%s: %s\ntry '%s --help'\n", name, strings.TrimPrefix(err.Error(), "fejkdata: "), name)
report(stderr, name, err)
fmt.Fprintf(stderr, "try '%s --help'\n", name)
return 2
}
// report writes err under the command name, in place of the library's own.
func report(stderr io.Writer, name string, err error) {
fmt.Fprintf(stderr, "%s: %s\n", name, strings.TrimPrefix(err.Error(), "fejkdata: "))
}
// fejkdataModule is the path of the module holding the library; the root package's path is
// the module's.
var fejkdataModule = reflect.TypeOf((*fejkdata.Generator)(nil)).Elem().PkgPath()
@@ -662,13 +672,15 @@ func versionLine(name string, info *debug.BuildInfo) string {
if info == nil {
return "fejkdata devel"
}
line := "fejkdata " + moduleVersion(info.Main)
if info.Main.Path == fejkdataModule {
return "fejkdata " + moduleVersion(info.Main)
}
for _, m := range info.Deps {
if m.Path == fejkdataModule {
line = name + " " + moduleVersion(info.Main) + ", fejkdata " + moduleVersion(*m)
return name + " " + moduleVersion(info.Main) + ", fejkdata " + moduleVersion(*m)
}
}
return line
return name + " " + moduleVersion(info.Main) + ", fejkdata devel"
}
// moduleVersion is the version m is built at: the replacement's where a replace directive
+4
View File
@@ -473,6 +473,10 @@ func TestRunNamesItselfByTheCommandName(t *testing.T) {
if code := run("mycli", shipped, nil, nil, &out, &errb); code != 2 || !strings.Contains(errb.String(), "| mycli\n") {
t.Errorf("mycli with nothing piped = %d, %q, want a pipe into mycli", code, errb.String())
}
errb.Reset()
if code := run("mycli", shipped, []string{"-d", "/nope"}, strings.NewReader("{/sv_SE.person}"), &out, &errb); code != 1 || !strings.HasPrefix(errb.String(), "mycli: ") {
t.Errorf("mycli -d /nope = %d, %q, want a load error under mycli", code, errb.String())
}
if code := run("mycli", shipped, []string{"--help"}, nil, &out, &errb); code != 0 || !strings.HasPrefix(out.String(), "Usage: <template> | mycli [flags]\n") || strings.Contains(out.String(), "fejkdata") {
t.Errorf("mycli --help = %d, %q, want mycli named throughout", code, out.String())
}
+1 -1
View File
@@ -366,7 +366,7 @@ GitHub has no `tags/{tag}` endpoint and answers 404 whether or not the tag exist
### 58. Ship prebuilt binaries, a container image, and packages for Homebrew, Scoop and the biggest Linux package managers, so the CLI needs no Go.
GoReleaser attaches the binaries to the release the tag workflow publishes, and builds deb and rpm packages, an Alpine APK and an AUR package beside Homebrew and Scoop. A checkout build prints `devel` for `--version`; the binaries carry the stamped tag. v0.1.0 ships first, so it can be tested before it is packaged.
GoReleaser attaches the binaries to the release the tag workflow publishes, and builds deb and rpm packages, an Alpine APK and an AUR package beside Homebrew and Scoop. The binaries carry the stamped tag, which `--version` prints. v0.1.0 ships first, so it can be tested before it is packaged.
### 206. Add `zh_CN` with its `geo/CN` tree.