Skip to content

Commit acfa153

Browse files
authored
output: Improve layout path construction
1 parent f033d9f commit acfa153

File tree

2 files changed

+60
-45
lines changed

2 files changed

+60
-45
lines changed

output/layout.go

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
package output
1515

1616
import (
17-
"fmt"
1817
"strings"
1918
"sync"
2019

@@ -65,7 +64,6 @@ func NewLayoutHandler() *LayoutHandler {
6564
// For returns a layout for the given LayoutDescriptor and options.
6665
// Layouts are rendered and cached internally.
6766
func (l *LayoutHandler) For(d LayoutDescriptor, f Format) ([]string, error) {
68-
6967
// We will get lots of requests for the same layouts, so avoid recalculations.
7068
key := layoutCacheKey{d, f.Name}
7169
l.mu.RLock()
@@ -131,7 +129,6 @@ func (l *layoutBuilder) addKind() {
131129
const renderingHookRoot = "/_markup"
132130

133131
func resolvePageTemplate(d LayoutDescriptor, f Format) []string {
134-
135132
b := &layoutBuilder{d: d, f: f}
136133

137134
if !d.RenderingHook && d.Layout != "" {
@@ -208,19 +205,17 @@ func resolvePageTemplate(d LayoutDescriptor, f Format) []string {
208205
}
209206

210207
return layouts
211-
212208
}
213209

214210
func (l *layoutBuilder) resolveVariations() []string {
215-
216211
var layouts []string
217212

218213
var variations []string
219214
name := strings.ToLower(l.f.Name)
220215

221216
if l.d.Lang != "" {
222217
// We prefer the most specific type before language.
223-
variations = append(variations, []string{fmt.Sprintf("%s.%s", l.d.Lang, name), name, l.d.Lang}...)
218+
variations = append(variations, []string{l.d.Lang + "." + name, name, l.d.Lang}...)
224219
} else {
225220
variations = append(variations, name)
226221
}
@@ -233,55 +228,63 @@ func (l *layoutBuilder) resolveVariations() []string {
233228
if variation == "" && layoutVar == "" {
234229
continue
235230
}
236-
template := layoutTemplate(typeVar, layoutVar)
237-
layouts = append(layouts, replaceKeyValues(template,
238-
"TYPE", typeVar,
239-
"LAYOUT", layoutVar,
240-
"VARIATIONS", variation,
241-
"EXTENSION", l.f.MediaType.Suffix(),
242-
))
231+
232+
s := constructLayoutPath(typeVar, layoutVar, variation, l.f.MediaType.Suffix())
233+
if s != "" {
234+
layouts = append(layouts, s)
235+
}
243236
}
244237
}
245-
246238
}
247239

248-
return filterDotLess(layouts)
240+
return layouts
249241
}
250242

251-
func layoutTemplate(typeVar, layoutVar string) string {
243+
// constructLayoutPath constructs a layout path given a type, layout,
244+
// variations, and extension. The path constructed follows the pattern of
245+
// type/layout.variations.extension. If any value is empty, it will be left out
246+
// of the path construction.
247+
//
248+
// Path construction requires at least 2 of 3 out of layout, variations, and extension.
249+
// If more than one of those is empty, an empty string is returned.
250+
func constructLayoutPath(typ, layout, variations, extension string) string {
251+
// we already know that layout and variations are not both empty because of
252+
// checks in resolveVariants().
253+
if extension == "" && (layout == "" || variations == "") {
254+
return ""
255+
}
256+
257+
// Commence valid path construction...
252258

253-
var l string
259+
var (
260+
p strings.Builder
261+
needDot bool
262+
)
254263

255-
if typeVar != "" {
256-
l = "TYPE/"
264+
if typ != "" {
265+
p.WriteString(typ)
266+
p.WriteString("/")
257267
}
258268

259-
if layoutVar != "" {
260-
l += "LAYOUT.VARIATIONS.EXTENSION"
261-
} else {
262-
l += "VARIATIONS.EXTENSION"
269+
if layout != "" {
270+
p.WriteString(layout)
271+
needDot = true
263272
}
264273

265-
return l
266-
}
267-
268-
func filterDotLess(layouts []string) []string {
269-
var filteredLayouts []string
270-
271-
for _, l := range layouts {
272-
l = strings.Replace(l, "..", ".", -1)
273-
l = strings.Trim(l, ".")
274-
// If media type has no suffix, we have "index" type of layouts in this list, which
275-
// doesn't make much sense.
276-
if strings.Contains(l, ".") {
277-
filteredLayouts = append(filteredLayouts, l)
274+
if variations != "" {
275+
if needDot {
276+
p.WriteString(".")
278277
}
278+
p.WriteString(variations)
279+
needDot = true
279280
}
280281

281-
return filteredLayouts
282-
}
282+
if extension != "" {
283+
if needDot {
284+
p.WriteString(".")
285+
}
286+
p.WriteString(extension)
287+
}
283288

284-
func replaceKeyValues(s string, oldNew ...string) string {
285-
replacer := strings.NewReplacer(oldNew...)
286-
return replacer.Replace(s)
289+
return p.String()
287290
}

output/layout_test.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -663,13 +663,25 @@ func TestLayout(t *testing.T) {
663663
}
664664

665665
func BenchmarkLayout(b *testing.B) {
666-
c := qt.New(b)
667666
descriptor := LayoutDescriptor{Kind: "taxonomy", Section: "categories"}
668667
l := NewLayoutHandler()
669668

670669
for i := 0; i < b.N; i++ {
671-
layouts, err := l.For(descriptor, HTMLFormat)
672-
c.Assert(err, qt.IsNil)
673-
c.Assert(layouts, qt.Not(qt.HasLen), 0)
670+
_, err := l.For(descriptor, HTMLFormat)
671+
if err != nil {
672+
panic(err)
673+
}
674+
}
675+
}
676+
677+
func BenchmarkLayoutUncached(b *testing.B) {
678+
for i := 0; i < b.N; i++ {
679+
descriptor := LayoutDescriptor{Kind: "taxonomy", Section: "categories"}
680+
l := NewLayoutHandler()
681+
682+
_, err := l.For(descriptor, HTMLFormat)
683+
if err != nil {
684+
panic(err)
685+
}
674686
}
675687
}

0 commit comments

Comments
 (0)