diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2017-05-01 18:40:34 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2017-05-01 21:44:15 +0200 |
commit | 690b0f8ff5795318dfa3834a5a75d6623e7d934a (patch) | |
tree | 1112306f4c6fecc0966d880dec702c3804633deb /tpl | |
parent | e2b067f0504ba41ef45786e2f83d7002bd13a7eb (diff) |
tpl: Add docshelper for template funcs
And fix some other minor related issues.
Updates #3418
Diffstat (limited to 'tpl')
-rw-r--r-- | tpl/cast/docshelper.go | 41 | ||||
-rw-r--r-- | tpl/cast/init.go | 28 | ||||
-rw-r--r-- | tpl/collections/init.go | 150 | ||||
-rw-r--r-- | tpl/compare/init.go | 60 | ||||
-rw-r--r-- | tpl/crypto/init.go | 39 | ||||
-rw-r--r-- | tpl/data/init.go | 22 | ||||
-rw-r--r-- | tpl/encoding/init.go | 39 | ||||
-rw-r--r-- | tpl/fmt/fmt.go | 13 | ||||
-rw-r--r-- | tpl/fmt/init.go | 35 | ||||
-rw-r--r-- | tpl/images/init.go | 17 | ||||
-rw-r--r-- | tpl/inflect/init.go | 43 | ||||
-rw-r--r-- | tpl/internal/templatefuncRegistry_test.go | 33 | ||||
-rw-r--r-- | tpl/internal/templatefuncsRegistry.go | 83 | ||||
-rw-r--r-- | tpl/lang/init.go | 18 | ||||
-rw-r--r-- | tpl/math/init.go | 64 | ||||
-rw-r--r-- | tpl/os/init.go | 34 | ||||
-rw-r--r-- | tpl/partials/init.go | 25 | ||||
-rw-r--r-- | tpl/safe/init.go | 67 | ||||
-rw-r--r-- | tpl/strings/init.go | 152 | ||||
-rw-r--r-- | tpl/time/init.go | 34 | ||||
-rw-r--r-- | tpl/tplimpl/template_funcs.go | 10 | ||||
-rw-r--r-- | tpl/tplimpl/template_funcs_test.go | 28 | ||||
-rw-r--r-- | tpl/transform/init.go | 99 | ||||
-rw-r--r-- | tpl/urls/init.go | 56 |
24 files changed, 842 insertions, 348 deletions
diff --git a/tpl/cast/docshelper.go b/tpl/cast/docshelper.go new file mode 100644 index 000000000..5220ca570 --- /dev/null +++ b/tpl/cast/docshelper.go @@ -0,0 +1,41 @@ +// Copyright 2017 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cast + +import ( + "github.com/spf13/hugo/deps" + "github.com/spf13/hugo/docshelper" + "github.com/spf13/hugo/tpl/internal" +) + +// This file provides documentation support and is randomly put into this package. +func init() { + docsProvider := func() map[string]interface{} { + docs := make(map[string]interface{}) + d := &deps.Deps{} + + var namespaces []*internal.TemplateFuncsNamespace + + for _, nsf := range internal.TemplateFuncsNamespaceRegistry { + nf := nsf(d) + namespaces = append(namespaces, nf) + + } + + docs["funcs"] = namespaces + return docs + } + + docshelper.AddDocProvider("tpl", docsProvider) +} diff --git a/tpl/cast/init.go b/tpl/cast/init.go index acddaa91a..1c737ee58 100644 --- a/tpl/cast/init.go +++ b/tpl/cast/init.go @@ -24,21 +24,27 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ "1234" | int | printf "%T" }}`, `int`}, - {`{{ 1234 | string | printf "%T" }}`, `string`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "int": ctx.ToInt, - "string": ctx.ToString, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.ToInt, + []string{"int"}, + [][2]string{ + {`{{ "1234" | int | printf "%T" }}`, `int`}, + }, + ) + + ns.AddMethodMapping(ctx.ToString, + []string{"string"}, + [][2]string{ + {`{{ 1234 | string | printf "%T" }}`, `string`}, + }, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/collections/init.go b/tpl/collections/init.go index 29f6809c3..289228901 100644 --- a/tpl/collections/init.go +++ b/tpl/collections/init.go @@ -24,48 +24,122 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New(d) - examples := [][2]string{ - {`{{ delimit (slice "A" "B" "C") ", " " and " }}`, `A, B and C`}, - {`{{ echoParam .Params "langCode" }}`, `en`}, - {`{{ if in "this string contains a substring" "substring" }}Substring found!{{ end }}`, `Substring found!`}, - { - `{{ (querify "foo" 1 "bar" 2 "baz" "with spaces" "qux" "this&that=those") | safeHTML }}`, - `bar=2&baz=with+spaces&foo=1&qux=this%26that%3Dthose`}, - { - `<a href="https://www.google.com?{{ (querify "q" "test" "page" 3) | safeURL }}">Search</a>`, - `<a href="https://www.google.com?page=3&q=test">Search</a>`}, - {`{{ slice "B" "C" "A" | sort }}`, `[A B C]`}, - {`{{ seq 3 }}`, `[1 2 3]`}, - {`{{ union (slice 1 2 3) (slice 3 4 5) }}`, `[1 2 3 4 5]`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "after": ctx.After, - "apply": ctx.Apply, - "delimit": ctx.Delimit, - "dict": ctx.Dictionary, - "echoParam": ctx.EchoParam, - "first": ctx.First, - "in": ctx.In, - "index": ctx.Index, - "intersect": ctx.Intersect, - "isSet": ctx.IsSet, - "isset": ctx.IsSet, - "last": ctx.Last, - "querify": ctx.Querify, - "shuffle": ctx.Shuffle, - "slice": ctx.Slice, - "sort": ctx.Sort, - "union": ctx.Union, - "where": ctx.Where, - "seq": ctx.Seq, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.After, + []string{"after"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Apply, + []string{"apply"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Delimit, + []string{"delimit"}, + [][2]string{ + {`{{ delimit (slice "A" "B" "C") ", " " and " }}`, `A, B and C`}, + }, + ) + + ns.AddMethodMapping(ctx.Dictionary, + []string{"dict"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.EchoParam, + []string{"echoParam"}, + [][2]string{ + {`{{ echoParam .Params "langCode" }}`, `en`}, + }, + ) + + ns.AddMethodMapping(ctx.First, + []string{"first"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.In, + []string{"in"}, + [][2]string{ + {`{{ if in "this string contains a substring" "substring" }}Substring found!{{ end }}`, `Substring found!`}, + }, + ) + + ns.AddMethodMapping(ctx.Index, + []string{"index"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Intersect, + []string{"intersect"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.IsSet, + []string{"isSet", "isset"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Last, + []string{"last"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Querify, + []string{"querify"}, + [][2]string{ + { + `{{ (querify "foo" 1 "bar" 2 "baz" "with spaces" "qux" "this&that=those") | safeHTML }}`, + `bar=2&baz=with+spaces&foo=1&qux=this%26that%3Dthose`}, + { + `<a href="https://www.google.com?{{ (querify "q" "test" "page" 3) | safeURL }}">Search</a>`, + `<a href="https://www.google.com?page=3&q=test">Search</a>`}, + }, + ) + + ns.AddMethodMapping(ctx.Shuffle, + []string{"shuffle"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Slice, + []string{"slice"}, + [][2]string{ + {`{{ slice "B" "C" "A" | sort }}`, `[A B C]`}, + }, + ) + + ns.AddMethodMapping(ctx.Sort, + []string{"sort"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Union, + []string{"union"}, + [][2]string{ + {`{{ union (slice 1 2 3) (slice 3 4 5) }}`, `[1 2 3 4 5]`}, + }, + ) + + ns.AddMethodMapping(ctx.Where, + []string{"where"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Seq, + []string{"seq"}, + [][2]string{ + {`{{ seq 3 }}`, `[1 2 3]`}, + }, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/compare/init.go b/tpl/compare/init.go index bf8227353..0285abff5 100644 --- a/tpl/compare/init.go +++ b/tpl/compare/init.go @@ -24,27 +24,53 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ if eq .Section "blog" }}current{{ end }}`, `current`}, - {`{{ "Hugo Rocks!" | default "Hugo Rules!" }}`, `Hugo Rocks!`}, - {`{{ "" | default "Hugo Rules!" }}`, `Hugo Rules!`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "default": ctx.Default, - "eq": ctx.Eq, - "ge": ctx.Ge, - "gt": ctx.Gt, - "le": ctx.Le, - "lt": ctx.Lt, - "ne": ctx.Ne, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.Default, + []string{"default"}, + [][2]string{ + {`{{ "Hugo Rocks!" | default "Hugo Rules!" }}`, `Hugo Rocks!`}, + {`{{ "" | default "Hugo Rules!" }}`, `Hugo Rules!`}, + }, + ) + + ns.AddMethodMapping(ctx.Eq, + []string{"eq"}, + [][2]string{ + {`{{ if eq .Section "blog" }}current{{ end }}`, `current`}, + }, + ) + + ns.AddMethodMapping(ctx.Ge, + []string{"ge"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Gt, + []string{"gt"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Le, + []string{"le"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Lt, + []string{"lt"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.Ne, + []string{"ne"}, + [][2]string{}, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/crypto/init.go b/tpl/crypto/init.go index 7c1899f88..a47c3369f 100644 --- a/tpl/crypto/init.go +++ b/tpl/crypto/init.go @@ -24,24 +24,35 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ md5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`}, - {`{{ crypto.MD5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`}, - {`{{ sha1 "Hello world, gophers!" }}`, `c8b5b0e33d408246e30f53e32b8f7627a7a649d4`}, - {`{{ sha256 "Hello world, gophers!" }}`, `6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "md5": ctx.MD5, - "sha1": ctx.SHA1, - "sha256": ctx.SHA256, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.MD5, + []string{"md5"}, + [][2]string{ + {`{{ md5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`}, + {`{{ crypto.MD5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`}, + }, + ) + + ns.AddMethodMapping(ctx.SHA1, + []string{"sha1"}, + [][2]string{ + {`{{ sha1 "Hello world, gophers!" }}`, `c8b5b0e33d408246e30f53e32b8f7627a7a649d4`}, + }, + ) + + ns.AddMethodMapping(ctx.SHA256, + []string{"sha256"}, + [][2]string{ + {`{{ sha256 "Hello world, gophers!" }}`, `6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46`}, + }, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/data/init.go b/tpl/data/init.go index 476e9ab75..e9e4ca2f9 100644 --- a/tpl/data/init.go +++ b/tpl/data/init.go @@ -24,19 +24,21 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New(d) - examples := [][2]string{ - {}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "getCSV": ctx.GetCSV, - "getJSON": ctx.GetJSON, - }, - Examples: examples, } + + ns.AddMethodMapping(ctx.GetCSV, + []string{"getCSV"}, + [][2]string{}, + ) + + ns.AddMethodMapping(ctx.GetJSON, + []string{"getJSON"}, + [][2]string{}, + ) + return ns } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/encoding/init.go b/tpl/encoding/init.go index 5bc0eb145..b46394203 100644 --- a/tpl/encoding/init.go +++ b/tpl/encoding/init.go @@ -24,24 +24,35 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ (slice "A" "B" "C") | jsonify }}`, `["A","B","C"]`}, - {`{{ "SGVsbG8gd29ybGQ=" | base64Decode }}`, `Hello world`}, - {`{{ 42 | base64Encode | base64Decode }}`, `42`}, - {`{{ "Hello world" | base64Encode }}`, `SGVsbG8gd29ybGQ=`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "base64Decode": ctx.Base64Decode, - "base64Encode": ctx.Base64Encode, - "jsonify": ctx.Jsonify, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.Base64Decode, + []string{"base64Decode"}, + [][2]string{ + {`{{ "SGVsbG8gd29ybGQ=" | base64Decode }}`, `Hello world`}, + {`{{ 42 | base64Encode | base64Decode }}`, `42`}, + }, + ) + + ns.AddMethodMapping(ctx.Base64Encode, + []string{"base64Encode"}, + [][2]string{ + {`{{ "Hello world" | base64Encode }}`, `SGVsbG8gd29ybGQ=`}, + }, + ) + + ns.AddMethodMapping(ctx.Jsonify, + []string{"jsonify"}, + [][2]string{ + {`{{ (slice "A" "B" "C") | jsonify }}`, `["A","B","C"]`}, + }, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/fmt/fmt.go b/tpl/fmt/fmt.go index 5e320fede..ca31ec522 100644 --- a/tpl/fmt/fmt.go +++ b/tpl/fmt/fmt.go @@ -26,14 +26,15 @@ func New() *Namespace { type Namespace struct { } -func (ns *Namespace) Print(a ...interface{}) (n int, err error) { - return _fmt.Print(a...) +func (ns *Namespace) Print(a ...interface{}) string { + return _fmt.Sprint(a...) } -func (ns *Namespace) Printf(format string, a ...interface{}) (n int, err error) { - return _fmt.Printf(format, a...) +func (ns *Namespace) Printf(format string, a ...interface{}) string { + return _fmt.Sprintf(format, a...) + } -func (ns *Namespace) Println(a ...interface{}) (n int, err error) { - return _fmt.Println(a...) +func (ns *Namespace) Println(a ...interface{}) string { + return _fmt.Sprintln(a...) } diff --git a/tpl/fmt/init.go b/tpl/fmt/init.go index 0f4296263..98070b777 100644 --- a/tpl/fmt/init.go +++ b/tpl/fmt/init.go @@ -24,18 +24,33 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ print "works!" }}`, `works!`}, - {`{{ printf "%s!" "works" }}`, `works!`}, - {`{{ println "works!" }}`, "works!\n"}, + ns := &internal.TemplateFuncsNamespace{ + Name: name, + Context: func() interface{} { return ctx }, } - return &internal.TemplateFuncsNamespace{ - Name: name, - Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{}, - Examples: examples, - } + ns.AddMethodMapping(ctx.Print, + []string{"print"}, + [][2]string{ + {`{{ print "works!" }}`, `works!`}, + }, + ) + + ns.AddMethodMapping(ctx.Println, + []string{"println"}, + [][2]string{ + {`{{ println "works!" }}`, "works!\n"}, + }, + ) + + ns.AddMethodMapping(ctx.Printf, + []string{"printf"}, + [][2]string{ + {`{{ printf "%s!" "works" }}`, `works!`}, + }, + ) + + return ns } diff --git a/tpl/images/init.go b/tpl/images/init.go index 0c2cb57c4..8e829f300 100644 --- a/tpl/images/init.go +++ b/tpl/images/init.go @@ -24,19 +24,18 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New(d) - examples := [][2]string{ - {}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "imageConfig": ctx.Config, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.Config, + []string{"imageConfig"}, + [][2]string{}, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/inflect/init.go b/tpl/inflect/init.go index b42ae5af3..50d012d35 100644 --- a/tpl/inflect/init.go +++ b/tpl/inflect/init.go @@ -24,26 +24,37 @@ func init() { f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { ctx := New() - examples := [][2]string{ - {`{{ humanize "my-first-post" }}`, `My first post`}, - {`{{ humanize "myCamelPost" }}`, `My camel post`}, - {`{{ humanize "52" }}`, `52nd`}, - {`{{ humanize 103 }}`, `103rd`}, - {`{{ "cat" | pluralize }}`, `cats`}, - {`{{ "cats" | singularize }}`, `cat`}, - } - - return &internal.TemplateFuncsNamespace{ + ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func() interface{} { return ctx }, - Aliases: map[string]interface{}{ - "humanize": ctx.Humanize, - "pluralize": ctx.Pluralize, - "singularize": ctx.Singularize, - }, - Examples: examples, } + ns.AddMethodMapping(ctx.Humanize, + []string{"humanize"}, + [][2]string{ + {`{{ humanize "my-first-post" }}`, `My first post`}, + {`{{ humanize "myCamelPost" }}`, `My camel post`}, + {`{{ humanize "52" }}`, `52nd`}, + {`{{ humanize 103 }}`, `103rd`}, + }, + ) + + ns.AddMethodMapping(ctx.Pluralize, + []string{"pluralize"}, + [][2]string{ + {`{{ "cat" | pluralize }}`, `cats`}, + }, + ) + + ns.AddMethodMapping(ctx.Singularize, + []string{"singularize"}, + [][2]string{ + {`{{ "cats" | singularize }}`, `cat`}, + }, + ) + + return ns + } internal.AddTemplateFuncsNamespace(f) diff --git a/tpl/internal/templatefuncRegistry_test.go b/tpl/internal/templatefuncRegistry_test.go new file mode 100644 index 000000000..dfc4ba09b --- /dev/null +++ b/tpl/internal/templatefuncRegistry_test.go @@ -0,0 +1,33 @@ +// Copyright 2017 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +type Test struct { +} + +func (t *Test) MyTestMethod() string { + return "abcde" +} + +func TestMethodToName(t *testing.T) { + test := &Test{} + + require.Equal(t, "MyTestMethod", methodToName(test.MyTestMethod)) +} 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, + } |