tpl: Add docshelper for template funcs

And fix some other minor related issues.

Updates #3418
This commit is contained in:
Bjørn Erik Pedersen
2017-05-01 18:40:34 +02:00
parent e2b067f050
commit 690b0f8ff5
25 changed files with 2064 additions and 347 deletions

View File

@@ -16,6 +16,12 @@
package internal
import (
"encoding/json"
"path/filepath"
"reflect"
"runtime"
"strings"
"github.com/spf13/hugo/deps"
)
@@ -32,12 +38,46 @@ type TemplateFuncsNamespace struct {
// This is the method receiver.
Context interface{}
// Additional info, aliases and examples, per method name.
MethodMappings map[string]TemplateFuncMethodMapping
}
func (t *TemplateFuncsNamespace) AddMethodMapping(m interface{}, aliases []string, examples [][2]string) {
if t.MethodMappings == nil {
t.MethodMappings = make(map[string]TemplateFuncMethodMapping)
}
name := methodToName(m)
// sanity check
for _, e := range examples {
if e[0] == "" {
panic(t.Name + ": Empty example for " + name)
}
}
for _, a := range aliases {
if a == "" {
panic(t.Name + ": Empty alias for " + name)
}
}
t.MethodMappings[name] = TemplateFuncMethodMapping{
Method: m,
Aliases: aliases,
Examples: examples,
}
}
type TemplateFuncMethodMapping struct {
Method interface{}
// Any template funcs aliases. This is mainly motivated by keeping
// backwards compability, but some new template funcs may also make
// sense to give short and snappy aliases.
// Note that these aliases are global and will be merged, so the last
// key will win.
Aliases map[string]interface{}
Aliases []string
// A slice of input/expected examples.
// We keep it a the namespace level for now, but may find a way to keep track
@@ -45,3 +85,44 @@ type TemplateFuncsNamespace struct {
// Some of these, hopefully just a few, may depend on some test data to run.
Examples [][2]string
}
func methodToName(m interface{}) string {
name := runtime.FuncForPC(reflect.ValueOf(m).Pointer()).Name()
name = filepath.Ext(name)
name = strings.TrimPrefix(name, ".")
name = strings.TrimSuffix(name, "-fm")
return name
}
func (t *TemplateFuncsNamespace) MarshalJSON() ([]byte, error) {
type Func struct {
Name string
Description string // TODO(bep)
Aliases []string
Examples [][2]string
}
// TODO(bep) map/lookup from docs template Namespace + Func name.
var funcs []Func
ctx := t.Context.(func() interface{})()
ctxType := reflect.TypeOf(ctx)
for i := 0; i < ctxType.NumMethod(); i++ {
method := ctxType.Method(i)
f := Func{
Name: method.Name,
}
if mapping, ok := t.MethodMappings[method.Name]; ok {
f.Aliases = mapping.Aliases
f.Examples = mapping.Examples
}
funcs = append(funcs, f)
}
return json.Marshal(&struct {
Name string
Funcs []Func
}{
Name: t.Name,
Funcs: funcs,
})
}