~bigbes/sr-ht-dolt

0190aab3497d337504118a6eb3f90001a37e3b92 — Eugene Blikh 5 days ago 231b776
web: register the views in one explicit list
4 files changed, 20 insertions(+), 25 deletions(-)

M web/beads.go
M web/memory.go
M web/milestones.go
M web/views.go
M web/beads.go => web/beads.go +0 -2
@@ 23,8 23,6 @@ import (
// hand-off of the request's ref and query.
type beadsView struct{}

func init() { RegisterView(&beadsView{}) }

func (*beadsView) Name() string     { return "beads" }
func (*beadsView) Label() string    { return "Beads" }
func (*beadsView) Template() string { return "beads.html" }

M web/memory.go => web/memory.go +0 -17
@@ 19,23 19,6 @@ import (
// label, template, and the hand-off of the request's ref and query.
type memoryView struct{}

// init registers the Memory view, and registers it *after* Milestones, which is
// where the design puts the tab: registration order is tab order (views.go).
//
// Getting that order is not free here, and the extra line is the whole reason
// this comment exists. A package's init functions run in lexical file-name
// order, and "memory.go" sorts before "milestones.go" — so registering only
// memoryView would put this tab between Beads and Milestones. Registering
// milestonesView first claims the slot ahead of it; milestones.go's own init
// then re-registers the same view, which RegisterView resolves in place (same
// Name), leaving the order alone. Both calls name real views, so a rename or a
// removal on either side is a compile error rather than a silently reordered
// tab bar.
func init() {
	RegisterView(&milestonesView{})
	RegisterView(&memoryView{})
}

func (*memoryView) Name() string     { return "memory" }
func (*memoryView) Label() string    { return "Memory" }
func (*memoryView) Template() string { return "memory.html" }

M web/milestones.go => web/milestones.go +0 -2
@@ 15,8 15,6 @@ import (
// The grouping itself lives in the beads package; this type is the View adapter.
type milestonesView struct{}

func init() { RegisterView(&milestonesView{}) }

func (*milestonesView) Name() string     { return "milestones" }
func (*milestonesView) Label() string    { return "Milestones" }
func (*milestonesView) Template() string { return "milestones.html" }

M web/views.go => web/views.go +20 -4
@@ 38,10 38,26 @@ type View interface {
// is what it is.
var registeredViews []View

// RegisterView adds v to the global registry. It is meant to be called from an
// init() in the file that defines a concrete view. If a view with the same
// Name() is already registered it is replaced, so double registration (e.g.
// from a duplicated init) is safe.
// init registers every view this service ships, in the order their tabs appear.
//
// The registration lives here, in one list, rather than in an init() beside each
// concrete view — which is where it used to be, and which made the tab order a
// consequence of file names. A package's init functions run in lexical file
// order, so "memory.go" registering itself would have put Memory between Beads
// and Milestones, and the only way to restore the intended order from inside
// memory.go was to register a view belonging to another file first. Tab order is
// a decision, and a decision that reads as a list of three lines cannot be
// changed by renaming a file.
func init() {
	RegisterView(&beadsView{})
	RegisterView(&milestonesView{})
	RegisterView(&memoryView{})
}

// RegisterView adds v to the global registry, appending it after everything
// registered before it: registration order is tab order. If a view with the same
// Name() is already registered it is replaced in place, so re-registering (a
// test swapping an implementation, say) never reorders the bar.
func RegisterView(v View) {
	for i, existing := range registeredViews {
		if existing.Name() == v.Name() {