From e583e42dfa8c5cc6befe847e5bad041e815cabf4 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Mon, 21 Sep 2026 10:38:57 +0200 Subject: [PATCH] Cut the vocabulary to what only it says, and fix what it got wrong --- README.md | 8 ++++---- doc.go | 38 +++++++++++++++----------------------- doc_test.go | 24 +++++++++++------------- todo.md | 3 +++ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index f6590d4..feddb0d 100644 --- a/README.md +++ b/README.md @@ -863,11 +863,11 @@ the Development section below, and who ships a register the four above then draw `secrets.GITHUB_TOKEN` resolve on either host, so only the names moved. - **The vocabulary sits below `doc.go`'s package clause, not in the package doc.** Goal 1 is what a developer choosing a library reads first, and the package doc is - that page: a glossary of unexported units would fill two thirds of it with names - no consumer can call, and Go doc comments have no code markup, so each one would + that page: the glossary would fill two thirds of it with the render path's units, + mostly unexported, and Go doc comments have no code markup, so every name would render its backticks literally. Below the clause it reaches goal 2's reader — who - opens the file — and nothing else. Valid while the glossary names units a consumer - cannot reach; one that came to name the exported API would belong above the clause. + opens the file — and nothing else. Valid while the glossary's subject is the render + path; one written to teach the exported API belongs above the clause. - **Options and fields share one namespace.** `format`, `weight`, `repeat`, `separator`, `datatype` and `drawGroup` are reserved; every other key is a field. Nesting fields under a key, or prefixing options, would tax every template to guard against a diff --git a/doc.go b/doc.go index 691ca0f..2f8e23d 100644 --- a/doc.go +++ b/doc.go @@ -16,31 +16,23 @@ package fejkdata // Vocabulary // -// The words the rest of the package uses, and the unit that owns each: -// -// - draw — one pick from a choice, or one row taken from a table, and the value -// the pick produced: `pick` and `drawn` settle a choice, `table.draw` a row, and -// `draw` carries what a read produced. -// - expansion — one render of one format, by `expand`. A nested template is an -// expansion of its own. +// - draw — one pick from a choice, or one row taken from a table, and the value a +// read produced: `pick`, `drawn`, `table.draw`, `draw`. +// - expansion — one render of one format: `expand`. // - render — what owns one `drawSet`, and so what one reference draw spans: -// `Generator.Fake`, `FakeRecord`, `FakeStruct`, `Template.Fake` and -// `RecordTemplate.Fake` each start one, as does `expandAnew` per iteration of a -// `template.repeat` — an iteration is an expansion and a render of its own. -// - hold — keeping one draw of a name, so every route to it reads that value. -// `template.held` lists what an expansion holds, `draws` keeps them and -// `readField` reads through it; a reference path is held for the whole render. -// - draw group — `template.drawGroup`, which gives the reference paths under it -// draws of their own inside the render. `drawSet` holds the unnamed group's and -// each named one's, and `drawScope` says which one a template renders in. -// - pin — fixing which row of a table the render uses. `draws.pin` pins it and the -// rows of its ancestors, and `draws.rowOf` draws one where none is pinned. +// `Generator.Fake`, `FakeRecord`, `Template.Fake` and `RecordTemplate.Fake` +// start one each, `FakeStruct` one per record, and `expandAnew` one per +// iteration of a `template.repeat`. +// - hold — keeping one draw of a name, so every route to it reads that value: +// `template.held`, `draws`, `readField`. +// - draw group — reference draws held apart inside one render: +// `template.drawGroup` as the data spells it, `template.drawGroupKey` as a +// render reads it, `drawSet`, `drawScope`. +// - pin — fixing which row of a table the render uses: `draws.pin`, `draws.rowOf`. // - family — a table and every table reaching it through a chain of // `table.parentT`, named by the root that chain ends at: `table.family`. // - whole — a read that lands on a `row`, so the row renders through its table's // format: `tableRead.whole` says a read did, `table.whole` is the node. -// - fence — a load-time check refusing data that two routes to one draw would -// disagree in, which is why a render cannot fail: `heldCheck` over an -// expansion's held names, `drawCheck` over a render's reference paths, and -// `checkFamilies` over the rows they pin. `New` runs them over the data set, -// `NewTemplate` and `FakeStruct` over what those compile. +// - fence — a load-time check, so rendering a compiled tree cannot fail: `New` +// runs them over the data set, `NewTemplate` and `FakeStruct` over what those +// compile. The draw fences are `heldCheck`, `drawCheck` and `checkFamilies`. diff --git a/doc_test.go b/doc_test.go index 258f7cd..476c14d 100644 --- a/doc_test.go +++ b/doc_test.go @@ -10,12 +10,10 @@ import ( "testing" ) -// Every backtick in the Vocabulary is a symbol, so an unrecognised spelling fails -// rather than going unchecked. -var backticked = regexp.MustCompile("`([^`]+)`") +// Every backtick in the Vocabulary is a symbol. +var backticked = regexp.MustCompile("`([^`\n]+)`") -// TestVocabularyNamesDeclaredSymbols proves the Vocabulary names symbols this -// package declares, so a renamed unit renames its entry with it. +// TestVocabularyNamesDeclaredSymbols holds a renamed unit to its Vocabulary entry. func TestVocabularyNamesDeclaredSymbols(t *testing.T) { files := sourceFiles(t) declared := declaredSymbols(files) @@ -50,23 +48,23 @@ func sourceFiles(t *testing.T) []*ast.File { func vocabulary(t *testing.T, files []*ast.File) string { t.Helper() - var found strings.Builder + var sections strings.Builder for _, f := range files { for _, c := range f.Comments { - if section, is := strings.CutPrefix(c.Text(), "Vocabulary\n\n"); is { - found.WriteString(section) + section, found := strings.CutPrefix(c.Text(), "Vocabulary\n\n") + if found && c.Pos() > f.Package { + sections.WriteString(section) } } } - if found.Len() == 0 { - t.Fatal("no comment opens with a Vocabulary heading, so fence, hold, pin and the rest are defined nowhere a reader of the code meets them") + if sections.Len() == 0 { + t.Fatal("no comment below a package clause opens with a Vocabulary heading, so the words the package is written in are defined nowhere a reader of the code meets them") } - return found.String() + return sections.String() } // declaredSymbols is every name the package declares at the top level, a method and -// a struct field keyed under its type: draws.pin, tableRead.whole. A name declared -// inside a function body is not one a Vocabulary entry may name. +// a struct field keyed under its type: draws.pin, tableRead.whole. func declaredSymbols(files []*ast.File) map[string]bool { names := map[string]bool{} for _, f := range files { diff --git a/todo.md b/todo.md index 6ea95de..1bf159f 100644 --- a/todo.md +++ b/todo.md @@ -43,6 +43,9 @@ This round, in order: - Spell one fresh draw set one way: `newDrawSet` exists, and `render.go` and `draw.go` hand-roll `drawSet{unnamed: draws{s: s}}` at three sites; name the lazy-map variant if the difference is deliberate. +- Run the package doc's Go example under test, as `readme_test.go` runs the README's + JSON blocks: `doc.go` and the README both print `Järvedsvägen 43\n891 77 Järved` + for seed 42, and nothing renders either, so a draw that moves leaves both false. ### Data