ref: acfa153863d6ff2acf17ffb4395e05d102229905
parent: f033d9f01d13d8cd08205ccfaa09919ed15dca77
author: Cameron Moore <moorereason@gmail.com>
date: Thu Oct 15 09:54:47 EDT 2020
output: Improve layout path construction
--- a/output/layout.go
+++ b/output/layout.go
@@ -14,7 +14,6 @@
package output
import (
- "fmt"
"strings"
"sync"
@@ -65,7 +64,6 @@
// For returns a layout for the given LayoutDescriptor and options.
// Layouts are rendered and cached internally.
func (l *LayoutHandler) For(d LayoutDescriptor, f Format) ([]string, error) {
-
// We will get lots of requests for the same layouts, so avoid recalculations.
key := layoutCacheKey{d, f.Name}
l.mu.RLock()
@@ -131,7 +129,6 @@
const renderingHookRoot = "/_markup"
func resolvePageTemplate(d LayoutDescriptor, f Format) []string {
-
b := &layoutBuilder{d: d, f: f}
if !d.RenderingHook && d.Layout != "" {
@@ -208,11 +205,9 @@
}
return layouts
-
}
func (l *layoutBuilder) resolveVariations() []string {
-
var layouts []string
var variations []string
@@ -220,7 +215,7 @@
if l.d.Lang != "" {
// We prefer the most specific type before language.
- variations = append(variations, []string{fmt.Sprintf("%s.%s", l.d.Lang, name), name, l.d.Lang}...)
+ variations = append(variations, []string{l.d.Lang + "." + name, name, l.d.Lang}...)
} else {
variations = append(variations, name)
}
@@ -233,55 +228,63 @@
if variation == "" && layoutVar == "" {
continue
}
- template := layoutTemplate(typeVar, layoutVar)
- layouts = append(layouts, replaceKeyValues(template,
- "TYPE", typeVar,
- "LAYOUT", layoutVar,
- "VARIATIONS", variation,
- "EXTENSION", l.f.MediaType.Suffix(),
- ))
+
+ s := constructLayoutPath(typeVar, layoutVar, variation, l.f.MediaType.Suffix())
+ if s != "" {
+ layouts = append(layouts, s)
+ }
}
}
-
}
- return filterDotLess(layouts)
+ return layouts
}
-func layoutTemplate(typeVar, layoutVar string) string {
+// constructLayoutPath constructs a layout path given a type, layout,
+// variations, and extension. The path constructed follows the pattern of
+// type/layout.variations.extension. If any value is empty, it will be left out
+// of the path construction.
+//
+// Path construction requires at least 2 of 3 out of layout, variations, and extension.
+// If more than one of those is empty, an empty string is returned.
+func constructLayoutPath(typ, layout, variations, extension string) string {
+ // we already know that layout and variations are not both empty because of
+ // checks in resolveVariants().
+ if extension == "" && (layout == "" || variations == "") {
+ return ""
+ }
- var l string
+ // Commence valid path construction...
- if typeVar != "" {
- l = "TYPE/"
+ var (
+ p strings.Builder
+ needDot bool
+ )
+
+ if typ != "" {
+ p.WriteString(typ)
+ p.WriteString("/")
}
- if layoutVar != "" {
- l += "LAYOUT.VARIATIONS.EXTENSION"
- } else {
- l += "VARIATIONS.EXTENSION"
+ if layout != "" {
+ p.WriteString(layout)
+ needDot = true
}
- return l
-}
+ if variations != "" {
+ if needDot {
+ p.WriteString(".")
+ }
+ p.WriteString(variations)
+ needDot = true
+ }
-func filterDotLess(layouts []string) []string {
- var filteredLayouts []string
-
- for _, l := range layouts {
- l = strings.Replace(l, "..", ".", -1)
- l = strings.Trim(l, ".")
- // If media type has no suffix, we have "index" type of layouts in this list, which
- // doesn't make much sense.
- if strings.Contains(l, ".") {
- filteredLayouts = append(filteredLayouts, l)
+ if extension != "" {
+ if needDot {
+ p.WriteString(".")
}
+ p.WriteString(extension)
}
- return filteredLayouts
-}
-
-func replaceKeyValues(s string, oldNew ...string) string {
- replacer := strings.NewReplacer(oldNew...)
- return replacer.Replace(s)
+ return p.String()
}
--- a/output/layout_test.go
+++ b/output/layout_test.go
@@ -663,13 +663,25 @@
}
func BenchmarkLayout(b *testing.B) {
- c := qt.New(b)
descriptor := LayoutDescriptor{Kind: "taxonomy", Section: "categories"}
l := NewLayoutHandler()
for i := 0; i < b.N; i++ {
- layouts, err := l.For(descriptor, HTMLFormat)
- c.Assert(err, qt.IsNil)
- c.Assert(layouts, qt.Not(qt.HasLen), 0)
+ _, err := l.For(descriptor, HTMLFormat)
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+func BenchmarkLayoutUncached(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ descriptor := LayoutDescriptor{Kind: "taxonomy", Section: "categories"}
+ l := NewLayoutHandler()
+
+ _, err := l.For(descriptor, HTMLFormat)
+ if err != nil {
+ panic(err)
+ }
}
}