diff options
Diffstat (limited to 'tpl/internal/templatefuncsRegistry.go')
-rw-r--r-- | tpl/internal/templatefuncsRegistry.go | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/tpl/internal/templatefuncsRegistry.go b/tpl/internal/templatefuncsRegistry.go index aa3196ca3..c9c931579 100644 --- a/tpl/internal/templatefuncsRegistry.go +++ b/tpl/internal/templatefuncsRegistry.go @@ -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, + }) +} |