Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+45
-1
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user