mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
tpl: Add docshelper for template funcs
And fix some other minor related issues. Updates #3418
This commit is contained in:
parent
e2b067f050
commit
690b0f8ff5
25 changed files with 2064 additions and 347 deletions
1223
docs/data/docs.json
1223
docs/data/docs.json
File diff suppressed because it is too large
Load diff
41
tpl/cast/docshelper.go
Normal file
41
tpl/cast/docshelper.go
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -24,21 +24,27 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ "1234" | int | printf "%T" }}`, `int`},
|
|
||||||
{`{{ 1234 | string | printf "%T" }}`, `string`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,47 +24,121 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
|
Name: name,
|
||||||
|
Context: func() interface{} { return ctx },
|
||||||
|
}
|
||||||
|
|
||||||
|
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`},
|
{`{{ 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`},
|
{`{{ 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!`},
|
{`{{ 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 }}`,
|
`{{ (querify "foo" 1 "bar" 2 "baz" "with spaces" "qux" "this&that=those") | safeHTML }}`,
|
||||||
`bar=2&baz=with+spaces&foo=1&qux=this%26that%3Dthose`},
|
`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?{{ (querify "q" "test" "page" 3) | safeURL }}">Search</a>`,
|
||||||
`<a href="https://www.google.com?page=3&q=test">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{
|
|
||||||
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.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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,27 +24,53 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ if eq .Section "blog" }}current{{ end }}`, `current`},
|
|
||||||
{`{{ "Hugo Rocks!" | default "Hugo Rules!" }}`, `Hugo Rocks!`},
|
|
||||||
{`{{ "" | default "Hugo Rules!" }}`, `Hugo Rules!`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,24 +24,35 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ md5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`},
|
|
||||||
{`{{ crypto.MD5 "Hello world, gophers!" }}`, `b3029f756f98f79e7f1b7f1d1f0dd53b`},
|
|
||||||
{`{{ sha1 "Hello world, gophers!" }}`, `c8b5b0e33d408246e30f53e32b8f7627a7a649d4`},
|
|
||||||
{`{{ sha256 "Hello world, gophers!" }}`, `6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,19 +24,21 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,24 +24,35 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ (slice "A" "B" "C") | jsonify }}`, `["A","B","C"]`},
|
|
||||||
{`{{ "SGVsbG8gd29ybGQ=" | base64Decode }}`, `Hello world`},
|
|
||||||
{`{{ 42 | base64Encode | base64Decode }}`, `42`},
|
|
||||||
{`{{ "Hello world" | base64Encode }}`, `SGVsbG8gd29ybGQ=`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -26,14 +26,15 @@ func New() *Namespace {
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Namespace) Print(a ...interface{}) (n int, err error) {
|
func (ns *Namespace) Print(a ...interface{}) string {
|
||||||
return _fmt.Print(a...)
|
return _fmt.Sprint(a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Namespace) Printf(format string, a ...interface{}) (n int, err error) {
|
func (ns *Namespace) Printf(format string, a ...interface{}) string {
|
||||||
return _fmt.Printf(format, a...)
|
return _fmt.Sprintf(format, a...)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Namespace) Println(a ...interface{}) (n int, err error) {
|
func (ns *Namespace) Println(a ...interface{}) string {
|
||||||
return _fmt.Println(a...)
|
return _fmt.Sprintln(a...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,19 +24,34 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ print "works!" }}`, `works!`},
|
|
||||||
{`{{ printf "%s!" "works" }}`, `works!`},
|
|
||||||
{`{{ println "works!" }}`, "works!\n"},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,19 +24,18 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,25 +24,36 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
|
Name: name,
|
||||||
|
Context: func() interface{} { return ctx },
|
||||||
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Humanize,
|
||||||
|
[]string{"humanize"},
|
||||||
|
[][2]string{
|
||||||
{`{{ humanize "my-first-post" }}`, `My first post`},
|
{`{{ humanize "my-first-post" }}`, `My first post`},
|
||||||
{`{{ humanize "myCamelPost" }}`, `My camel post`},
|
{`{{ humanize "myCamelPost" }}`, `My camel post`},
|
||||||
{`{{ humanize "52" }}`, `52nd`},
|
{`{{ humanize "52" }}`, `52nd`},
|
||||||
{`{{ humanize 103 }}`, `103rd`},
|
{`{{ humanize 103 }}`, `103rd`},
|
||||||
{`{{ "cat" | pluralize }}`, `cats`},
|
|
||||||
{`{{ "cats" | singularize }}`, `cat`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &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.Pluralize,
|
||||||
|
[]string{"pluralize"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "cat" | pluralize }}`, `cats`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Singularize,
|
||||||
|
[]string{"singularize"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "cats" | singularize }}`, `cat`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
33
tpl/internal/templatefuncRegistry_test.go
Normal file
33
tpl/internal/templatefuncRegistry_test.go
Normal file
|
@ -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))
|
||||||
|
}
|
|
@ -16,6 +16,12 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/hugo/deps"
|
"github.com/spf13/hugo/deps"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,12 +38,46 @@ type TemplateFuncsNamespace struct {
|
||||||
// This is the method receiver.
|
// This is the method receiver.
|
||||||
Context interface{}
|
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
|
// Any template funcs aliases. This is mainly motivated by keeping
|
||||||
// backwards compability, but some new template funcs may also make
|
// backwards compability, but some new template funcs may also make
|
||||||
// sense to give short and snappy aliases.
|
// sense to give short and snappy aliases.
|
||||||
// Note that these aliases are global and will be merged, so the last
|
// Note that these aliases are global and will be merged, so the last
|
||||||
// key will win.
|
// key will win.
|
||||||
Aliases map[string]interface{}
|
Aliases []string
|
||||||
|
|
||||||
// A slice of input/expected examples.
|
// A slice of input/expected examples.
|
||||||
// We keep it a the namespace level for now, but may find a way to keep track
|
// 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.
|
// Some of these, hopefully just a few, may depend on some test data to run.
|
||||||
Examples [][2]string
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -24,20 +24,18 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
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)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,29 +24,55 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{"{{add 1 2}}", "3"},
|
|
||||||
{"{{div 6 3}}", "2"},
|
|
||||||
{"{{mod 15 3}}", "0"},
|
|
||||||
{"{{modBool 15 3}}", "true"},
|
|
||||||
{"{{mul 2 3}}", "6"},
|
|
||||||
{"{{sub 3 2}}", "1"},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"add": ctx.Add,
|
|
||||||
"div": ctx.Div,
|
|
||||||
"mod": ctx.Mod,
|
|
||||||
"modBool": ctx.ModBool,
|
|
||||||
"mul": ctx.Mul,
|
|
||||||
"sub": ctx.Sub,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Add,
|
||||||
|
[]string{"add"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{add 1 2}}", "3"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Div,
|
||||||
|
[]string{"div"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{div 6 3}}", "2"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Mod,
|
||||||
|
[]string{"mod"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{mod 15 3}}", "0"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.ModBool,
|
||||||
|
[]string{"modBool"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{modBool 15 3}}", "true"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Mul,
|
||||||
|
[]string{"mul"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{mul 2 3}}", "6"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Sub,
|
||||||
|
[]string{"sub"},
|
||||||
|
[][2]string{
|
||||||
|
{"{{sub 3 2}}", "1"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,22 +24,32 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ range (readDir ".") }}{{ .Name }}{{ end }}`, "README.txt"},
|
|
||||||
{`{{ readFile "README.txt" }}`, `Hugo Rocks!`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"getenv": ctx.Getenv,
|
|
||||||
"readDir": ctx.ReadDir,
|
|
||||||
"readFile": ctx.ReadFile,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Getenv,
|
||||||
|
[]string{"getenv"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.ReadDir,
|
||||||
|
[]string{"readDir"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ range (readDir ".") }}{{ .Name }}{{ end }}`, "README.txt"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.ReadFile,
|
||||||
|
[]string{"readFile"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ readFile "README.txt" }}`, `Hugo Rocks!`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,20 +24,25 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ partial "header.html" . }}`, `<title>Hugo Rocks!</title>`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"partial": ctx.Include,
|
|
||||||
"partialCached": ctx.getCached,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Include,
|
||||||
|
[]string{"partial"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ partial "header.html" . }}`, `<title>Hugo Rocks!</title>`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.getCached,
|
||||||
|
[]string{"partialCached"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,30 +24,57 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ "Bat&Man" | safeCSS | safeCSS }}`, `Bat&Man`},
|
|
||||||
{`{{ "Bat&Man" | safeHTML | safeHTML }}`, `Bat&Man`},
|
|
||||||
{`{{ "Bat&Man" | safeHTML }}`, `Bat&Man`},
|
|
||||||
{`{{ "(1*2)" | safeJS | safeJS }}`, `(1*2)`},
|
|
||||||
{`{{ "http://gohugo.io" | safeURL | safeURL }}`, `http://gohugo.io`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"safeCSS": ctx.CSS,
|
|
||||||
"safeHTML": ctx.HTML,
|
|
||||||
"safeHTMLAttr": ctx.HTMLAttr,
|
|
||||||
"safeJS": ctx.JS,
|
|
||||||
"safeJSStr": ctx.JSStr,
|
|
||||||
"safeURL": ctx.URL,
|
|
||||||
"sanitizeURL": ctx.SanitizeURL,
|
|
||||||
"sanitizeurl": ctx.SanitizeURL,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.CSS,
|
||||||
|
[]string{"safeCSS"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "Bat&Man" | safeCSS | safeCSS }}`, `Bat&Man`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.HTML,
|
||||||
|
[]string{"safeHTML"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "Bat&Man" | safeHTML | safeHTML }}`, `Bat&Man`},
|
||||||
|
{`{{ "Bat&Man" | safeHTML }}`, `Bat&Man`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.HTMLAttr,
|
||||||
|
[]string{"safeHTMLAttr"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.JS,
|
||||||
|
[]string{"safeJS"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "(1*2)" | safeJS | safeJS }}`, `(1*2)`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.JSStr,
|
||||||
|
[]string{"safeJSStr"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.URL,
|
||||||
|
[]string{"safeURL"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "http://gohugo.io" | safeURL | safeURL }}`, `http://gohugo.io`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.SanitizeURL,
|
||||||
|
[]string{"sanitizeURL", "sanitizeurl"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,53 +24,117 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
|
Name: name,
|
||||||
|
Context: func() interface{} { return ctx },
|
||||||
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Chomp,
|
||||||
|
[]string{"chomp"},
|
||||||
|
[][2]string{
|
||||||
{`{{chomp "<p>Blockhead</p>\n" }}`, `<p>Blockhead</p>`},
|
{`{{chomp "<p>Blockhead</p>\n" }}`, `<p>Blockhead</p>`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.CountRunes,
|
||||||
|
[]string{"countrunes"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.CountWords,
|
||||||
|
[]string{"countwords"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.FindRE,
|
||||||
|
[]string{"findRE"},
|
||||||
|
[][2]string{
|
||||||
{
|
{
|
||||||
`{{ findRE "[G|g]o" "Hugo is a static side generator written in Go." "1" }}`,
|
`{{ findRE "[G|g]o" "Hugo is a static side generator written in Go." "1" }}`,
|
||||||
`[go]`},
|
`[go]`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.HasPrefix,
|
||||||
|
[]string{"hasPrefix"},
|
||||||
|
[][2]string{
|
||||||
{`{{ hasPrefix "Hugo" "Hu" }}`, `true`},
|
{`{{ hasPrefix "Hugo" "Hu" }}`, `true`},
|
||||||
{`{{ hasPrefix "Hugo" "Fu" }}`, `false`},
|
{`{{ hasPrefix "Hugo" "Fu" }}`, `false`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.ToLower,
|
||||||
|
[]string{"lower"},
|
||||||
|
[][2]string{
|
||||||
{`{{lower "BatMan"}}`, `batman`},
|
{`{{lower "BatMan"}}`, `batman`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Replace,
|
||||||
|
[]string{"replace"},
|
||||||
|
[][2]string{
|
||||||
{
|
{
|
||||||
`{{ replace "Batman and Robin" "Robin" "Catwoman" }}`,
|
`{{ replace "Batman and Robin" "Robin" "Catwoman" }}`,
|
||||||
`Batman and Catwoman`},
|
`Batman and Catwoman`},
|
||||||
{
|
},
|
||||||
`{{ "http://gohugo.io/docs" | replaceRE "^https?://([^/]+).*" "$1" }}`,
|
)
|
||||||
`gohugo.io`},
|
|
||||||
|
ns.AddMethodMapping(ctx.ReplaceRE,
|
||||||
|
[]string{"replaceRE"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.SliceString,
|
||||||
|
[]string{"slicestr"},
|
||||||
|
[][2]string{
|
||||||
{`{{slicestr "BatMan" 0 3}}`, `Bat`},
|
{`{{slicestr "BatMan" 0 3}}`, `Bat`},
|
||||||
{`{{slicestr "BatMan" 3}}`, `Man`},
|
{`{{slicestr "BatMan" 3}}`, `Man`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Split,
|
||||||
|
[]string{"split"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Substr,
|
||||||
|
[]string{"substr"},
|
||||||
|
[][2]string{
|
||||||
{`{{substr "BatMan" 0 -3}}`, `Bat`},
|
{`{{substr "BatMan" 0 -3}}`, `Bat`},
|
||||||
{`{{substr "BatMan" 3 3}}`, `Man`},
|
{`{{substr "BatMan" 3 3}}`, `Man`},
|
||||||
{`{{title "Bat man"}}`, `Bat Man`},
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Trim,
|
||||||
|
[]string{"trim"},
|
||||||
|
[][2]string{
|
||||||
{`{{ trim "++Batman--" "+-" }}`, `Batman`},
|
{`{{ trim "++Batman--" "+-" }}`, `Batman`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Title,
|
||||||
|
[]string{"title"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{title "Bat man"}}`, `Bat Man`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Truncate,
|
||||||
|
[]string{"truncate"},
|
||||||
|
[][2]string{
|
||||||
{`{{ "this is a very long text" | truncate 10 " ..." }}`, `this is a ...`},
|
{`{{ "this is a very long text" | truncate 10 " ..." }}`, `this is a ...`},
|
||||||
{`{{ "With [Markdown](/markdown) inside." | markdownify | truncate 14 }}`, `With <a href="/markdown">Markdown …</a>`},
|
{`{{ "With [Markdown](/markdown) inside." | markdownify | truncate 14 }}`, `With <a href="/markdown">Markdown …</a>`},
|
||||||
{`{{upper "BatMan"}}`, `BATMAN`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
|
||||||
Context: func() interface{} { return ctx },
|
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"chomp": ctx.Chomp,
|
|
||||||
"countrunes": ctx.CountRunes,
|
|
||||||
"countwords": ctx.CountWords,
|
|
||||||
"findRE": ctx.FindRE,
|
|
||||||
"hasPrefix": ctx.HasPrefix,
|
|
||||||
"lower": ctx.ToLower,
|
|
||||||
"replace": ctx.Replace,
|
|
||||||
"replaceRE": ctx.ReplaceRE,
|
|
||||||
"slicestr": ctx.SliceString,
|
|
||||||
"split": ctx.Split,
|
|
||||||
"substr": ctx.Substr,
|
|
||||||
"title": ctx.Title,
|
|
||||||
"trim": ctx.Trim,
|
|
||||||
"truncate": ctx.Truncate,
|
|
||||||
"upper": ctx.ToUpper,
|
|
||||||
},
|
},
|
||||||
Examples: examples,
|
)
|
||||||
}
|
|
||||||
|
ns.AddMethodMapping(ctx.ToUpper,
|
||||||
|
[]string{"upper"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{upper "BatMan"}}`, `BATMAN`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,22 +24,32 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ (time "2015-01-21").Year }}`, `2015`},
|
|
||||||
{`dateFormat: {{ dateFormat "Monday, Jan 2, 2006" "2015-01-21" }}`, `dateFormat: Wednesday, Jan 21, 2015`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"dateFormat": ctx.Format,
|
|
||||||
"now": ctx.Now,
|
|
||||||
"time": ctx.AsTime,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Format,
|
||||||
|
[]string{"dateFormat"},
|
||||||
|
[][2]string{
|
||||||
|
{`dateFormat: {{ dateFormat "Monday, Jan 2, 2006" "2015-01-21" }}`, `dateFormat: Wednesday, Jan 21, 2015`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Now,
|
||||||
|
[]string{"now"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.AsTime,
|
||||||
|
[]string{"asTime"}, // TODO(bep) handle duplicate
|
||||||
|
[][2]string{
|
||||||
|
{`{{ (asTime "2015-01-21").Year }}`, `2015`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -51,8 +51,14 @@ func (t *templateFuncster) initFuncMap() {
|
||||||
panic(ns.Name + " is a duplicate template func")
|
panic(ns.Name + " is a duplicate template func")
|
||||||
}
|
}
|
||||||
funcMap[ns.Name] = ns.Context
|
funcMap[ns.Name] = ns.Context
|
||||||
for k, v := range ns.Aliases {
|
for _, mm := range ns.MethodMappings {
|
||||||
funcMap[k] = v
|
for _, alias := range mm.Aliases {
|
||||||
|
if _, exists := funcMap[alias]; exists {
|
||||||
|
panic(alias + " is a duplicate template func")
|
||||||
|
}
|
||||||
|
funcMap[alias] = mm.Method
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,8 @@ func TestTemplateFuncsExamples(t *testing.T) {
|
||||||
|
|
||||||
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
||||||
ns := nsf(d)
|
ns := nsf(d)
|
||||||
for i, example := range ns.Examples {
|
for _, mm := range ns.MethodMappings {
|
||||||
|
for i, example := range mm.Examples {
|
||||||
in, expected := example[0], example[1]
|
in, expected := example[0], example[1]
|
||||||
d.WithTemplate = func(templ tpl.TemplateHandler) error {
|
d.WithTemplate = func(templ tpl.TemplateHandler) error {
|
||||||
require.NoError(t, templ.AddTemplate("test", in))
|
require.NoError(t, templ.AddTemplate("test", in))
|
||||||
|
@ -103,6 +104,7 @@ func TestTemplateFuncsExamples(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,47 +24,72 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ "I :heart: Hugo" | emojify }}`, `I ❤️ Hugo`},
|
|
||||||
{`{{ .Title | markdownify}}`, `<strong>BatMan</strong>`},
|
|
||||||
{`{{ plainify "Hello <strong>world</strong>, gophers!" }}`, `Hello world, gophers!`},
|
|
||||||
{
|
|
||||||
`htmlEscape 1: {{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | safeHTML}}`,
|
|
||||||
`htmlEscape 1: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
{
|
|
||||||
`htmlEscape 2: {{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>"}}`,
|
|
||||||
`htmlEscape 2: Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;`},
|
|
||||||
{
|
|
||||||
`htmlUnescape 1: {{htmlUnescape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | safeHTML}}`,
|
|
||||||
`htmlUnescape 1: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
{
|
|
||||||
`htmlUnescape 2: {{"Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;" | htmlUnescape | htmlUnescape | safeHTML}}`,
|
|
||||||
`htmlUnescape 2: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
{
|
|
||||||
`htmlUnescape 3: {{"Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;" | htmlUnescape | htmlUnescape }}`,
|
|
||||||
`htmlUnescape 3: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
{
|
|
||||||
`htmlUnescape 4: {{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | htmlUnescape | safeHTML }}`,
|
|
||||||
`htmlUnescape 4: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
{
|
|
||||||
`htmlUnescape 5: {{ htmlUnescape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | htmlEscape | safeHTML }}`,
|
|
||||||
`htmlUnescape 5: Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"emojify": ctx.Emojify,
|
|
||||||
"highlight": ctx.Highlight,
|
|
||||||
"htmlEscape": ctx.HTMLEscape,
|
|
||||||
"htmlUnescape": ctx.HTMLUnescape,
|
|
||||||
"markdownify": ctx.Markdownify,
|
|
||||||
"plainify": ctx.Plainify,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Emojify,
|
||||||
|
[]string{"emojify"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ "I :heart: Hugo" | emojify }}`, `I ❤️ Hugo`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Highlight,
|
||||||
|
[]string{"highlight"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.HTMLEscape,
|
||||||
|
[]string{"htmlEscape"},
|
||||||
|
[][2]string{
|
||||||
|
{
|
||||||
|
`{{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | safeHTML}}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
{
|
||||||
|
`{{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>"}}`,
|
||||||
|
`Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;`},
|
||||||
|
{
|
||||||
|
`{{ htmlEscape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | htmlUnescape | safeHTML }}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.HTMLUnescape,
|
||||||
|
[]string{"htmlUnescape"},
|
||||||
|
[][2]string{
|
||||||
|
{
|
||||||
|
`{{ htmlUnescape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | safeHTML}}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
{
|
||||||
|
`{{"Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;" | htmlUnescape | htmlUnescape | safeHTML}}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
{
|
||||||
|
`{{"Cathal Garvey &amp; The Sunshine Band &lt;cathal@foo.bar&gt;" | htmlUnescape | htmlUnescape }}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
{
|
||||||
|
`{{ htmlUnescape "Cathal Garvey & The Sunshine Band <cathal@foo.bar>" | htmlEscape | safeHTML }}`,
|
||||||
|
`Cathal Garvey & The Sunshine Band <cathal@foo.bar>`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Markdownify,
|
||||||
|
[]string{"markdownify"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ .Title | markdownify}}`, `<strong>BatMan</strong>`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.Plainify,
|
||||||
|
[]string{"plainify"},
|
||||||
|
[][2]string{
|
||||||
|
{`{{ plainify "Hello <strong>world</strong>, gophers!" }}`, `Hello world, gophers!`},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
|
@ -24,33 +24,43 @@ func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d)
|
||||||
|
|
||||||
examples := [][2]string{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
{`{{ "index.html" | absLangURL }}`, `http://mysite.com/hugo/en/index.html`},
|
|
||||||
{`{{ "http://gohugo.io/" | absURL }}`, `http://gohugo.io/`},
|
|
||||||
{`{{ "mystyle.css" | absURL }}`, `http://mysite.com/hugo/mystyle.css`},
|
|
||||||
{`{{ 42 | absURL }}`, `http://mysite.com/hugo/42`},
|
|
||||||
{`{{ "index.html" | relLangURL }}`, `/hugo/en/index.html`},
|
|
||||||
{`{{ "http://gohugo.io/" | relURL }}`, `http://gohugo.io/`},
|
|
||||||
{`{{ "mystyle.css" | relURL }}`, `/hugo/mystyle.css`},
|
|
||||||
{`{{ mul 2 21 | relURL }}`, `/hugo/42`},
|
|
||||||
{`{{ "Bat Man" | urlize }}`, `bat-man`},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &internal.TemplateFuncsNamespace{
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Context: func() interface{} { return ctx },
|
Context: func() interface{} { return ctx },
|
||||||
Aliases: map[string]interface{}{
|
|
||||||
"absURL": ctx.AbsURL,
|
|
||||||
"absLangURL": ctx.AbsLangURL,
|
|
||||||
"ref": ctx.Ref,
|
|
||||||
"relURL": ctx.RelURL,
|
|
||||||
"relLangURL": ctx.RelLangURL,
|
|
||||||
"relref": ctx.RelRef,
|
|
||||||
"urlize": ctx.URLize,
|
|
||||||
},
|
|
||||||
Examples: examples,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.AbsURL,
|
||||||
|
[]string{"absURL"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns.AddMethodMapping(ctx.AbsLangURL,
|
||||||
|
[]string{"absLangURL"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
ns.AddMethodMapping(ctx.Ref,
|
||||||
|
[]string{"ref"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
ns.AddMethodMapping(ctx.RelURL,
|
||||||
|
[]string{"relURL"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
ns.AddMethodMapping(ctx.RelLangURL,
|
||||||
|
[]string{"relLangURL"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
ns.AddMethodMapping(ctx.RelRef,
|
||||||
|
[]string{"relref"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
ns.AddMethodMapping(ctx.URLize,
|
||||||
|
[]string{"urlize"},
|
||||||
|
[][2]string{},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ns
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.AddTemplateFuncsNamespace(f)
|
internal.AddTemplateFuncsNamespace(f)
|
||||||
|
|
Loading…
Reference in a new issue