Show a struct filling an address from one pick, a record template compiled once, a counter per table and how a custom CLI's embed maps to paths, and record the custom-CLI builder's ruling on the help

This commit is contained in:
2026-10-11 23:27:33 +02:00
committed by Lillem4n
parent 9671600fff
commit 1edc3b57dd
3 changed files with 21 additions and 8 deletions
+17 -4
View File
@@ -352,6 +352,8 @@ v = t.Fake() // render many times,
r, err := f.FakeRecord("users") // one record: each field a column r, err := f.FakeRecord("users") // one record: each field a column
s := r.JSON() // {"first":"Ada","last":"Lovelace"} s := r.JSON() // {"first":"Ada","last":"Lovelace"}
r, err = f.FakeRecordTemplate(`{"format":"{x}","x":["a","b"]}`) // compile + render inline r, err = f.FakeRecordTemplate(`{"format":"{x}","x":["a","b"]}`) // compile + render inline
rt, err := f.NewRecordTemplate(`{"format":"","id":"{seq(users)}"}`) // compile a record once
r = rt.Fake() // render a row; loop this for bulk output
err = f.FakeStruct(&user) // fill a struct's fake:"…" tagged fields err = f.FakeStruct(&user) // fill a struct's fake:"…" tagged fields
ok, err := fejkdata.IsTemplate(arg) // an inline template by its shape, else a path ok, err := fejkdata.IsTemplate(arg) // an inline template by its shape, else a path
``` ```
@@ -363,7 +365,8 @@ ok, err := fejkdata.IsTemplate(arg) // an inline template by its shape, el
| `WithDataFS(modules...)` | layer modules in order, each an `fs.FS`: a shipped package's `Modules()...`, or your own `embed.FS`; `WithDataFS()` loads none | | `WithDataFS(modules...)` | layer modules in order, each an `fs.FS`: a shipped package's `Modules()...`, or your own `embed.FS`; `WithDataFS()` loads none |
A shipped package's `Modules()` returns its own `FS` and every module it reads, such as a A shipped package's `Modules()` returns its own `FS` and every module it reads, such as a
locale's country's places. Your program links only the packages it imports. locale's country's places; `misc.*` comes from `misc.Modules()`, in
`github.com/larvit/fejkdata/data/misc`. Your program links only the packages it imports.
`data.Modules()`, from `github.com/larvit/fejkdata/data`, is every shipped module, and `data.Modules()`, from `github.com/larvit/fejkdata/data`, is every shipped module, and
links all of them. Two locales, with `enus` from `github.com/larvit/fejkdata/data/en_US`, links all of them. Two locales, with `enus` from `github.com/larvit/fejkdata/data/en_US`,
are `WithDataFS(append(svse.Modules(), enus.Modules()...)...)`. To stand in your are `WithDataFS(append(svse.Modules(), enus.Modules()...)...)`. To stand in your
@@ -389,7 +392,7 @@ A path, wherever a call takes one, may start with one `/`, as a reference does.
A `*Record` carries its columns via `Columns()` — each a `Column` of `Name`, A `*Record` carries its columns via `Columns()` — each a `Column` of `Name`,
`DataType`, rendered `Value` and `Null` — and serializes them with `JSON()` `DataType`, rendered `Value` and `Null` — and serializes them with `JSON()`
(one object), `CSVHeader()`/`CSVLine()`, or `SQLInsert(table)` — the shapes the (one object), `CSVHeader()`/`CSVLine()`, or `SQLInsert(table)` — the shapes the
CLI's `--format` writes. `FakeRecord` and `FakeRecordTemplate` take a record; a CLI's `--format` writes, each without a trailing newline. `FakeRecord` and `FakeRecordTemplate` take a record; a
path or template that is not one — a bare string, a choice of more than one item, or a path or template that is not one — a bare string, a choice of more than one item, or a
folder — errors. folder — errors.
@@ -401,6 +404,12 @@ type User struct {
Nick *string `fake:"[null, \"{/sv_SE.username}\"]"` Nick *string `fake:"[null, \"{/sv_SE.username}\"]"`
Home Address // filled from Address's own tags Home Address // filled from Address's own tags
} }
type Address struct {
Street string `fake:"{/sv_SE.address as a}{a.street} {a.street-number}"`
PostalCode string `fake:"{a.postal-code}"` // the same address's code
Locality string `fake:"{a.locality}"`
}
``` ```
`FakeStruct` fills a struct through a pointer: each exported field tagged `fake:"…"` is `FakeStruct` fills a struct through a pointer: each exported field tagged `fake:"…"` is
@@ -447,7 +456,10 @@ var mydata embed.FS
func main() { os.Exit(cli.Main(append(data.Modules(), mydata)...)) } func main() { os.Exit(cli.Main(append(data.Modules(), mydata)...)) }
``` ```
Add `*.tsv` to the embed where your data holds a table. The CLI takes `fejkdata`'s flags The embed's folders are the paths: `//go:embed acme` serves `acme/customer.json` as
`{/acme.customer}`. Add `*.tsv` to the embed where your data holds a table. The CLI loads
its data when it runs, so a test calling `fejkdata.New(fejkdata.WithDataFS(...))` over the
same modules catches broken data at `go test`. 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 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. `--version` prints your module's version beside the fejkdata version it is built with.
@@ -768,7 +780,8 @@ Rejected at `New`: a bound that is no calendar date, or after the other; an unqu
or double-quoted layout, naming the single-quoted one; and `time` with a layout naming a or double-quoted layout, naming the single-quoted one; and `time` with a layout naming a
date field, naming `date`, since `time` draws no date. `{seq()}` spans `Fake` date field, naming `date`, since `time` draws no date. `{seq()}` spans `Fake`
calls and `repeat`, resets with a new generator, and is the natural primary key for calls and `repeat`, resets with a new generator, and is the natural primary key for
the SQL example above. the SQL example above; give each table its own counter, `{seq(orders)}`, where one
generator fills several.
### Computation ### Computation
+2 -2
View File
@@ -139,7 +139,7 @@ A directory a machine happens to have would make `--seed 42` machine-dependent;
## The shipped data is Go packages a library imports by choice, and the CLI carries every one, from 0.1.0 ## The shipped data is Go packages a library imports by choice, and the CLI carries every one, from 0.1.0
2026-10-04, Lilleman auf Larv; revised 2026-10-09 to put the packages in the core's Go module. Serves goals 2.2, 6.2, 7.3, 9 and 10.1. Carried out by `todo.md` items 181, 185, 186 and 196. The CLI binary may grow to hundreds of MB. 2026-10-04, Lilleman auf Larv; revised 2026-10-09 to put the packages in the core's Go module. Serves goals 2.2, 6.2, 7.3, 9 and 10.1. Carried out by `todo.md` items 181, 186 and 196. The CLI binary may grow to hundreds of MB.
- One Go package per locale, one per country's `geo` tree, and one for `misc`, all in the core's Go module. A package registers nothing when imported. - One Go package per locale, one per country's `geo` tree, and one for `misc`, all in the core's Go module. A package registers nothing when imported.
- A bare `New()` loads no data and fails, naming the option to add. `WithoutShippedData` goes. - A bare `New()` loads no data and fails, naming the option to add. `WithoutShippedData` goes.
@@ -149,7 +149,7 @@ A directory a machine happens to have would make `--seed 42` machine-dependent;
- In the CLI, a flag of its own says a `--data-path` replaces what it clashes with, so flags still go anywhere on the line. Data authors and hand fixture authors bench it. - In the CLI, a flag of its own says a `--data-path` replaces what it clashes with, so flags still go anywhere on the line. Data authors and hand fixture authors bench it.
- The README asks for functions with no side effects of their own. - The README asks for functions with no side effects of their own.
- The CLI is a library call. One exported list names every shipped package, and `fejkdata`'s own `main` passes it to that call. The list lives in a package of its own, so a library importing the core links no data it did not import. A custom CLI is the same few lines with other modules added. No API and no flag exists only for custom CLIs; `Main` tells one apart only by its build info and file name, so its help and errors carry its name and its `--version` its own module's version beside fejkdata's. The maintainer chose so on 2026-10-11. - The CLI is a library call. One exported list names every shipped package, and `fejkdata`'s own `main` passes it to that call. The list lives in a package of its own, so a library importing the core links no data it did not import. A custom CLI is the same few lines with other modules added. No API and no flag exists only for custom CLIs; `Main` tells one apart only by its build info and file name, so its help and errors carry its name and its `--version` its own module's version beside fejkdata's. The maintainer chose so on 2026-10-11.
- Before the module API ships, a panel of the README's audience personas tries pulling in data with it. - The help's examples and its hint for an empty stdin read no data, so each renders in any custom CLI; `--list` points to the paths. "Shipped data", in `--no-shipped-data` and in `-d`'s help, names the modules passed to `Main`, a custom CLI's own included. A custom-CLI builder ruled so on 2026-10-11, in the audience bench that preceded the module API's release.
Valid while the shipped data stays under 100 MiB, which a gate test holds (`todo.md` item 192): `go get` fetches the whole Go module, and the `go` command refuses a Go module zip over 500 MiB (`MaxZipFile` in `golang.org/x/mod/zip`). Past it, `todo.md` item 193 moves the largest packages into nested Go modules that keep their import paths, each requiring the core release that drops the package, so no build sees it twice. Valid while the shipped data stays under 100 MiB, which a gate test holds (`todo.md` item 192): `go get` fetches the whole Go module, and the `go` command refuses a Go module zip over 500 MiB (`MaxZipFile` in `golang.org/x/mod/zip`). Past it, `todo.md` item 193 moves the largest packages into nested Go modules that keep their import paths, each requiring the core release that drops the package, so no build sees it twice.
+2 -2
View File
@@ -92,8 +92,8 @@ func (loadError) Is(target error) bool { return target == ErrLoad }
// winning a name clash; it fails where no [WithDataFS] or [WithDataPath] names the data // winning a name clash; it fails where no [WithDataFS] or [WithDataPath] names the data
// to load. Each JSON file becomes a category named after the file (address.json -> // to load. Each JSON file becomes a category named after the file (address.json ->
// "address") and each subdirectory a namespace segment. It errors on a missing // "address") and each subdirectory a namespace segment. It errors on a missing
// directory, invalid JSON or invalid data; a generator with no data at all renders // directory, invalid JSON or invalid data. WithDataFS() alone loads no data, and the
// templates that read none. A source whose .fejkdata.json carries an index, as each // generator renders templates that read none. A source whose .fejkdata.json carries an index, as each
// shipped module's does, loads each category on the first call reaching it. Data failing // shipped module's does, loads each category on the first call reaching it. Data failing
// to load, in New or on that first call, gives an error matching [ErrLoad]. // to load, in New or on that first call, gives an error matching [ErrLoad].
func New(opts ...Option) (*Generator, error) { func New(opts ...Option) (*Generator, error) {