summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-05-01 18:40:34 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-05-01 21:44:15 +0200
commit690b0f8ff5795318dfa3834a5a75d6623e7d934a (patch)
tree1112306f4c6fecc0966d880dec702c3804633deb /tpl
parente2b067f0504ba41ef45786e2f83d7002bd13a7eb (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.go41
-rw-r--r--tpl/cast/init.go28
-rw-r--r--tpl/collections/init.go150
-rw-r--r--tpl/compare/init.go60
-rw-r--r--tpl/crypto/init.go39
-rw-r--r--tpl/data/init.go22
-rw-r--r--tpl/encoding/init.go39
-rw-r--r--tpl/fmt/fmt.go13
-rw-r--r--tpl/fmt/init.go35
-rw-r--r--tpl/images/init.go17
-rw-r--r--tpl/inflect/init.go43
-rw-r--r--tpl/internal/templatefuncRegistry_test.go33
-rw-r--r--tpl/internal/templatefuncsRegistry.go83
-rw-r--r--tpl/lang/init.go18
-rw-r--r--tpl/math/init.go64
-rw-r--r--tpl/os/init.go34
-rw-r--r--tpl/partials/init.go25
-rw-r--r--tpl/safe/init.go67
-rw-r--r--tpl/strings/init.go152
-rw-r--r--tpl/time/init.go34
-rw-r--r--tpl/tplimpl/template_funcs.go10
-rw-r--r--tpl/tplimpl/template_funcs_test.go28
-rw-r--r--tpl/transform/init.go99
-rw-r--r--tpl/urls/init.go56
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&amp;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&amp;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,
+ })
+}
diff --git a/tpl/lang/init.go b/tpl/lang/init.go
index a902c7a66..6cf8e790d 100644
--- a/tpl/lang/init.go
+++ b/tpl/lang/init.go
@@ -24,20 +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{}{
- "i18n": ctx.Translate,
- "T": ctx.Translate,
- },
- Examples: examples,
}
+ ns.AddMethodMapping(ctx.Translate,
+ []string{"i18n", "T"},
+ [][2]string{},
+ )
+
+ return ns
+
}
internal.AddTemplateFuncsNamespace(f)
diff --git a/tpl/math/init.go b/tpl/math/init.go
index 69ba2cc17..65b22c516 100644
--- a/tpl/math/init.go<