Answer architecture round 4: New keeps every module the loaded manifests read, and the note on a failed load names them all from one function beside noDataNote, so no category carries its source's modules
This commit is contained in:
+2
-2
@@ -131,8 +131,8 @@ replacement, and each removed path, column or flag.
|
||||
and the CLI carries them all. `New` loads the modules `WithDataFS(modules...)` names and
|
||||
the folders `WithDataPath` names, and fails, naming `WithDataFS`, where no such option
|
||||
is given. A manifest's `reads` lists the modules its source reads by default, and a
|
||||
reference to a path nothing provides fails, naming those modules or saying there are
|
||||
none.
|
||||
reference to a path nothing provides fails to load, naming every module the loaded
|
||||
manifests read, or saying there are none.
|
||||
- A data source whose root holds a `.fejkdata.json` manifest with an `index` loads each
|
||||
category on the first call reaching it, as each shipped module does. Data failing to load,
|
||||
in `New` or on that first call, gives an error matching `ErrLoad`, and the CLI exits 1.
|
||||
|
||||
@@ -195,8 +195,9 @@ A manifest's `reads` lists, by any name its author chooses, every module the sou
|
||||
references read unless another source provides the same paths, directly or through
|
||||
another module; a manifest may carry it without an index. Nothing loads these modules:
|
||||
pass them yourself. A shipped module names a Go package: `sv_SE`'s manifest reads
|
||||
`github.com/larvit/fejkdata/data/geo/SE`. A reference to a path nothing provides fails,
|
||||
naming those modules, or saying the manifest names none.
|
||||
`github.com/larvit/fejkdata/data/geo/SE`. Data whose reference names a path nothing
|
||||
provides fails to load, naming every module the loaded manifests read, or saying they
|
||||
name none.
|
||||
|
||||
Each locale carries `address`, `color`, `company`, `date`, `email`, `first-name`,
|
||||
`ip`, `last-name`, `person`, `phone`, `price`, `sentence`, `sex`, `time`, `url`,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package fejkdata
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/larvit/fejkdata/internal/datafiles"
|
||||
@@ -8,22 +9,31 @@ import (
|
||||
|
||||
// loadSources merges sources in order, the last winning a clash. A source whose manifest
|
||||
// carries an index leaves its categories unloaded; every other source loads here, with
|
||||
// the unloaded categories it needs.
|
||||
func loadSources(sources []datafiles.Source) (folder, error) {
|
||||
// the unloaded categories it needs. It also returns, sorted, every module the sources'
|
||||
// manifests read by default.
|
||||
// docs/decisions.md#a-source-whose-manifest-carries-an-index-loads-each-category-on-first-reach-any-other-loads-in-new-with-what-it-reads
|
||||
func loadSources(sources []datafiles.Source) (folder, []string, error) {
|
||||
root := folder{children: map[string]node{}}
|
||||
var modules []string
|
||||
for _, src := range sources {
|
||||
if err := addSource(&root, src); err != nil {
|
||||
return folder{}, err
|
||||
m, err := src.Manifest()
|
||||
if err != nil {
|
||||
return folder{}, nil, err
|
||||
}
|
||||
if err := addSource(&root, src, m); err != nil {
|
||||
return folder{}, nil, err
|
||||
}
|
||||
for _, module := range m.Reads {
|
||||
if !slices.Contains(modules, module) {
|
||||
modules = append(modules, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
return root, loadReached(&root, categorySites(&root), nil)
|
||||
slices.Sort(modules)
|
||||
return root, modules, loadReached(&root, categorySites(&root), nil)
|
||||
}
|
||||
|
||||
func addSource(root *folder, src datafiles.Source) error {
|
||||
m, err := src.Manifest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func addSource(root *folder, src datafiles.Source, m datafiles.Manifest) error {
|
||||
if m.Index != nil {
|
||||
placeIndex(root, src, m.Index)
|
||||
return nil
|
||||
|
||||
+5
-3
@@ -31,6 +31,8 @@ type Generator struct {
|
||||
drawState *drawstate.State
|
||||
root folder // the categories as the node a path walks from, owned here so a walk allocates none
|
||||
structs map[reflect.Type]structResult
|
||||
// defaultModules is every module the loaded sources' manifests read by default.
|
||||
defaultModules []string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@@ -107,15 +109,15 @@ func New(opts ...Option) (*Generator, error) {
|
||||
if c.err != nil {
|
||||
return nil, c.err
|
||||
}
|
||||
root, err := loadSources(c.sources)
|
||||
root, modules, err := loadSources(c.sources)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fejkdata: %w", loadError{err})
|
||||
return nil, fmt.Errorf("fejkdata: %w", withDefaultModules(loadError{err}, modules))
|
||||
}
|
||||
seed, err := c.drawSeed()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fejkdata: %w", err)
|
||||
}
|
||||
return &Generator{drawState: drawstate.New(seed), root: root}, nil
|
||||
return &Generator{drawState: drawstate.New(seed), root: root, defaultModules: modules}, nil
|
||||
}
|
||||
|
||||
// List returns the sorted dotted paths Fake renders: each category and every field,
|
||||
|
||||
@@ -59,7 +59,7 @@ func (f *Generator) loadCallerPath(path string) (string, []string, error) {
|
||||
}
|
||||
if c, ok := categoryOn(&f.root, segs); ok && c.unloaded() {
|
||||
if err := loadReached(&f.root, nil, []categoryAt{c}); err != nil {
|
||||
return "", nil, fmt.Errorf("fejkdata: %w", loadError{err})
|
||||
return "", nil, fmt.Errorf("fejkdata: %w", withDefaultModules(loadError{err}, f.defaultModules))
|
||||
}
|
||||
}
|
||||
return path, segs, nil
|
||||
|
||||
@@ -37,7 +37,7 @@ func (f *Generator) NewTemplate(input string) (*Template, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if err := loadInline(&f.root, n, "template", false); err != nil {
|
||||
return nil, f.noDataNote(fmt.Errorf("fejkdata: %w", err))
|
||||
return nil, f.noDataNote(fmt.Errorf("fejkdata: %w", withDefaultModules(err, f.defaultModules)))
|
||||
}
|
||||
return &Template{g: f, n: n}, nil
|
||||
}
|
||||
|
||||
@@ -121,6 +121,19 @@ type noEntry struct{ seg string }
|
||||
|
||||
func (e noEntry) Error() string { return fmt.Sprintf("no entry %q", e.seg) }
|
||||
|
||||
// withDefaultModules adds to err, where data fails to load because a segment names nothing, the
|
||||
// modules the loaded sources' manifests read by default, or that they name none.
|
||||
func withDefaultModules(err error, modules []string) error {
|
||||
var ne noEntry
|
||||
if !errors.Is(err, ErrLoad) || !errors.As(err, &ne) {
|
||||
return err
|
||||
}
|
||||
if len(modules) == 0 {
|
||||
return fmt.Errorf("%w, and no loaded module names a module it reads by default", err)
|
||||
}
|
||||
return fmt.Errorf("%w; the loaded modules read by default %s", err, strings.Join(modules, ", "))
|
||||
}
|
||||
|
||||
// noDataNote adds to err, where a segment names nothing and f holds no data at all, that no
|
||||
// data is loaded.
|
||||
func (f *Generator) noDataNote(err error) error {
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// templateSite is a template to resolve, with its folder and category, both empty for an inline
|
||||
// template, and eachNode's label for it.
|
||||
// templateSite is a template to resolve, with its folder, empty for an inline template, and
|
||||
// eachNode's label for it.
|
||||
type templateSite struct {
|
||||
t *template
|
||||
folder []string
|
||||
|
||||
@@ -31,7 +31,7 @@ func (f *Generator) FakeStruct(v any) error {
|
||||
defer f.mu.Unlock()
|
||||
shape, err := f.structShapeOf(p.Elem().Type())
|
||||
if err != nil {
|
||||
return fmt.Errorf("fejkdata: %w", err)
|
||||
return fmt.Errorf("fejkdata: %w", withDefaultModules(err, f.defaultModules))
|
||||
}
|
||||
shape.fill(f.drawState, p.Elem())
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user