From 9e786ccf39ab9643880fa7956e32ff2187c468ac Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 29 Sep 2026 21:44:39 +0200 Subject: [PATCH] Move the read fold to reads.go and the survey's verdict to drawfence.go, deleting readsurvey.go --- README.md | 4 +-- drawfence.go | 33 +++++++++++++++++++++ drawfence_test.go | 46 ++++++++++++++++++++++++++++- readsurvey.go => reads.go | 33 --------------------- readsurvey_test.go => reads_test.go | 40 ------------------------- 5 files changed, 80 insertions(+), 76 deletions(-) rename readsurvey.go => reads.go (91%) rename readsurvey_test.go => reads_test.go (71%) diff --git a/README.md b/README.md index a2e1888..0bb4537 100644 --- a/README.md +++ b/README.md @@ -885,8 +885,8 @@ inline.go inline templates: Template, NewTemplate, FakeTemplate, IsTemplat format.go the {token} grammar: scanning, tokens, operands, validation, compiling a format draws.go the memo a hold or draw group keeps its draws in; and a render's draws and the scope it reads its reference paths through holdfence.go the load fences over the hold: the routes and spellings that read one held name two ways -drawfence.go the load fences over reference draws and their refusals: a drawGroup's, a render's and a record's columns judged on the survey, and a table reaching its own family -readsurvey.go the load-time survey of what a render reads, and what a path reads of a table family +drawfence.go the load fences over reference draws and their refusals: a drawGroup's, a render's and a record's columns judged on what they read, and a table reaching its own family +reads.go the load-time fold of what a render reads, and what a path reads of a table family pins.go the pin set: the table rows a render fixes, which the draw fences replay reference.go reference sigils, and binding references across the tree graph.go the node graph: tree walks, containment and render edges, and the cycle and repeat fences diff --git a/drawfence.go b/drawfence.go index 4d0a6a5..926ed57 100644 --- a/drawfence.go +++ b/drawfence.go @@ -14,6 +14,39 @@ type drawFence struct { fold *readFold } +// readSurvey is what one render reads, gathered at load for check to compare. +type readSurvey struct { + reads []pathRead + clash *pinClash +} + +// pinClash is the first read whose selectors clash with a row its route pinned. +type pinClash struct { + route surveyRoute + spelling string + err error +} + +// survey is the fold's result as a render in group: every read not inside a nested draw group +// draws in it, and one read gathered by several routes is kept once. +func survey(reads []pathRead, group string) *readSurvey { + s := &readSurvey{} + for _, r := range reads { + if r.clash != nil { + if s.clash == nil { + s.clash = &pinClash{r.at.route, r.a.spelling, r.clash} + } + continue + } + if r.at.group == "" { + r.at.group = group + } + s.reads = append(s.reads, r) + } + s.reads = distinct(s.reads) + return s +} + // checkDrawGroup refuses a draw group that splits nothing: one whose render reads every reference // path inside a repeat or a nested draw group, which draw apart from it whatever it names. func (f *drawFence) checkDrawGroup(path string, n node) error { diff --git a/drawfence_test.go b/drawfence_test.go index 1e30a0d..bed94b0 100644 --- a/drawfence_test.go +++ b/drawfence_test.go @@ -1,6 +1,10 @@ package fejkdata -import "testing" +import ( + "strings" + "testing" + "testing/fstest" +) func fenceCorpus(t *testing.T) *Generator { t.Helper() @@ -175,3 +179,43 @@ func eachRenderSet(reads []pathRead, fn func([]pathRead)) { } grow(nil, reads, nil) } + +func TestReadSurveyReportsAPinClashAsAnError(t *testing.T) { + fsys := fstest.MapFS{ + "r.json": {Data: []byte(`"{/y[a].v}"`)}, + "n.json": {Data: []byte(`{"format":"{f}","f":"{/y[a].v}"}`)}, + "x.json": {Data: []byte(`{"format":"{v}","rows":"x.tsv","key":"code"}`)}, + "x.tsv": {Data: []byte("code\tv\n1\tb\n2\tc\n")}, + "y.json": {Data: []byte(`{"format":"{v}","rows":"y.tsv","key":"code","parent":"x"}`)}, + "y.tsv": {Data: []byte("code\tv\tx\na\t{/x[2].v}\t1\nb\tz\t2\n")}, + } + g, err := loadDir(dataSource{fsys: fsys}, ".") + if err != nil { + t.Fatalf("loadDir = %v", err) + } + if err := treeBinding(g.children).link(); err != nil { + t.Fatalf("link = %v", err) + } + r, isTemplate := g.children["r"].(*template) + if !isTemplate { + t.Fatalf("r is a %T, want a template", g.children["r"]) + } + if err := surveyRender(newReadFold(), r).check(); err == nil || !strings.Contains(err.Error(), "two rows of") { + t.Errorf("check = %v, want y[a]'s row of x clashing with x[2] named, whatever order the fences run in", err) + } + n, isTemplate := g.children["n"].(*template) + if !isTemplate { + t.Fatalf("n is a %T, want a template", g.children["n"]) + } + if err := surveyRender(newReadFold(), n).check(); err == nil || !strings.HasPrefix(err.Error(), "{f} with {/x[2].v}: x[1] and x[2] are two rows of x") { + t.Errorf("check = %v, want the clash below {f} named by the route the root reaches it by", err) + } +} + +func surveyRender(f *readFold, t *template) *readSurvey { + return survey(f.rootReads(t), t.link.drawGroupKey) +} + +func surveyColumns(f *readFold, t *template, columns []string) *readSurvey { + return survey(f.columnReads(t, columns), t.link.drawGroupKey) +} diff --git a/readsurvey.go b/reads.go similarity index 91% rename from readsurvey.go rename to reads.go index ebf3736..d56e33d 100644 --- a/readsurvey.go +++ b/reads.go @@ -2,19 +2,6 @@ package fejkdata import "fmt" -// readSurvey is what one render reads, gathered at load for check to compare. -type readSurvey struct { - reads []pathRead - clash *pinClash -} - -// pinClash is the first read whose selectors clash with a row its route pinned. -type pinClash struct { - route surveyRoute - spelling string - err error -} - // surveyAt is where a read sits in its render: the draw group it draws in ("" until the // root names one), how the render's root reached it, the rows pinned above it, and the rows // of whole draws whose cells it sits in. @@ -70,26 +57,6 @@ func (f *readFold) columnReads(t *template, columns []string) []pathRead { return reads } -// survey is the fold's result as a render in group: every read not inside a nested draw group -// draws in it, and one read gathered by several routes is kept once. -func survey(reads []pathRead, group string) *readSurvey { - s := &readSurvey{} - for _, r := range reads { - if r.clash != nil { - if s.clash == nil { - s.clash = &pinClash{r.at.route, r.a.spelling, r.clash} - } - continue - } - if r.at.group == "" { - r.at.group = group - } - s.reads = append(s.reads, r) - } - s.reads = distinct(s.reads) - return s -} - // reads is what rendering n reads, short of a repeat, which renders over draws of its own: each // read with the rows pinned above it inside n, and in its draw group where a template inside n // names one. diff --git a/readsurvey_test.go b/reads_test.go similarity index 71% rename from readsurvey_test.go rename to reads_test.go index f7a7ee0..3b33c7e 100644 --- a/readsurvey_test.go +++ b/reads_test.go @@ -137,43 +137,3 @@ func TestReadSurveyWalksACellByEveryRoute(t *testing.T) { t.Errorf("{/z} gathered under a pinned row %v and a whole read's row %v, want both: {/g} reaches x's cells from the root, and {/x} renders them whole", pinned, whole) } } - -func TestReadSurveyReportsAPinClashAsAnError(t *testing.T) { - fsys := fstest.MapFS{ - "r.json": {Data: []byte(`"{/y[a].v}"`)}, - "n.json": {Data: []byte(`{"format":"{f}","f":"{/y[a].v}"}`)}, - "x.json": {Data: []byte(`{"format":"{v}","rows":"x.tsv","key":"code"}`)}, - "x.tsv": {Data: []byte("code\tv\n1\tb\n2\tc\n")}, - "y.json": {Data: []byte(`{"format":"{v}","rows":"y.tsv","key":"code","parent":"x"}`)}, - "y.tsv": {Data: []byte("code\tv\tx\na\t{/x[2].v}\t1\nb\tz\t2\n")}, - } - g, err := loadDir(dataSource{fsys: fsys}, ".") - if err != nil { - t.Fatalf("loadDir = %v", err) - } - if err := treeBinding(g.children).link(); err != nil { - t.Fatalf("link = %v", err) - } - r, isTemplate := g.children["r"].(*template) - if !isTemplate { - t.Fatalf("r is a %T, want a template", g.children["r"]) - } - if err := surveyRender(newReadFold(), r).check(); err == nil || !strings.Contains(err.Error(), "two rows of") { - t.Errorf("check = %v, want y[a]'s row of x clashing with x[2] named, whatever order the fences run in", err) - } - n, isTemplate := g.children["n"].(*template) - if !isTemplate { - t.Fatalf("n is a %T, want a template", g.children["n"]) - } - if err := surveyRender(newReadFold(), n).check(); err == nil || !strings.HasPrefix(err.Error(), "{f} with {/x[2].v}: x[1] and x[2] are two rows of x") { - t.Errorf("check = %v, want the clash below {f} named by the route the root reaches it by", err) - } -} - -func surveyRender(f *readFold, t *template) *readSurvey { - return survey(f.rootReads(t), t.link.drawGroupKey) -} - -func surveyColumns(f *readFold, t *template, columns []string) *readSurvey { - return survey(f.columnReads(t, columns), t.link.drawGroupKey) -}