shithub: hugo

Download patch

ref: 13435a6f608306c5094fdcd72a1d9538727f91b2
parent: 07b96d16e8679c40e289c9076ef4414ed6eb7f81
author: David E. Wheeler <[email protected]>
date: Sat Jun 2 22:55:37 EDT 2018

tpl: Add strings.Repeat


--- /dev/null
+++ b/docs/content/en/functions/strings.Repeat.md
@@ -1,0 +1,31 @@
+---
+title: strings.Repeat
+# linktitle:
+description: Returns a string consisting of count copies of the string s.
+godocref:
+date: 2018-05-31
+publishdate: 2018-05-31
+lastmod: 2018-05-31
+categories: [functions]
+menu:
+  docs:
+    parent: "functions"
+keywords: [strings]
+signature: ["strings.Repeat INPUT COUNT"]
+workson: []
+hugoversion:
+relatedfuncs: []
+deprecated: false
+---
+
+`strings.Repeat` provides the Go [`strings.Repeat`](https://golang.org/pkg/strings/#Repeat) function for Hugo templates. It takes a string and a count, and returns a string with consisting of count copies of the string argument.
+
+```
+{{ strings.Repeat "yo" 3 }} → "yoyoyo"
+```
+
+`strings.Repeat` *requires* the second argument, which tells the function how many times to repeat the first argument; there is no default. However, it can be used as a pipeline:
+
+```
+{{ "yo" | strings.Repeat 3 }} → "yoyoyo"
+```
--- a/docs/data/docs.json
+++ b/docs/data/docs.json
@@ -3410,6 +3410,20 @@
             ]
           ]
         },
+        "Repeat": {
+          "Description": "Repeat returns a new string consisting of count copies of the string s.",
+          "Args": [
+            "s",
+            "n"
+          ],
+          "Aliases": null,
+          "Examples": [
+            [
+              "{{ \"yo\" | strings.Repeat 4 }}",
+              "yoyoyoyo"
+            ]
+          ]
+        },
         "Truncate": {
           "Description": "Truncate truncates a given string to the specified length.",
           "Args": [
--- a/tpl/strings/init.go
+++ b/tpl/strings/init.go
@@ -158,6 +158,13 @@
 			},
 		)
 
+		ns.AddMethodMapping(ctx.Repeat,
+			nil,
+			[][2]string{
+				{`{{ "yo" | strings.Repeat 4 }}`, `yoyoyoyo`},
+			},
+		)
+
 		ns.AddMethodMapping(ctx.ToUpper,
 			[]string{"upper"},
 			[][2]string{
--- a/tpl/strings/strings.go
+++ b/tpl/strings/strings.go
@@ -17,6 +17,7 @@
 	"errors"
 	"fmt"
 	"html/template"
+	"math"
 	_strings "strings"
 	"unicode/utf8"
 
@@ -416,4 +417,24 @@
 	}
 
 	return _strings.TrimSuffix(ss, sx), nil
+}
+
+// Repeat returns a new string consisting of count copies of the string s.
+// The count is limited to an in16 value (up to 32767).
+func (ns *Namespace) Repeat(n, s interface{}) (string, error) {
+	ss, err := cast.ToStringE(s)
+	if err != nil {
+		return "", err
+	}
+
+	sn, err := cast.ToIntE(n)
+	if err != nil {
+		return "", err
+	}
+
+	if sn > math.MaxInt16 {
+		return "", fmt.Errorf("Cannot repeat string more than %d times", math.MaxInt16)
+	}
+
+	return _strings.Repeat(ss, sn), nil
 }
--- a/tpl/strings/strings_test.go
+++ b/tpl/strings/strings_test.go
@@ -16,6 +16,7 @@
 import (
 	"fmt"
 	"html/template"
+	"math"
 	"testing"
 
 	"github.com/gohugoio/hugo/deps"
@@ -699,6 +700,41 @@
 		errMsg := fmt.Sprintf("[%d] %v", i, test)
 
 		result, err := ns.TrimSuffix(test.suffix, test.s)
+
+		if b, ok := test.expect.(bool); ok && !b {
+			require.Error(t, err, errMsg)
+			continue
+		}
+
+		require.NoError(t, err, errMsg)
+		assert.Equal(t, test.expect, result, errMsg)
+	}
+}
+
+func TestRepeat(t *testing.T) {
+	t.Parallel()
+
+	for i, test := range []struct {
+		s      interface{}
+		n      interface{}
+		expect interface{}
+	}{
+		{"yo", "2", "yoyo"},
+		{"~", "16", "~~~~~~~~~~~~~~~~"},
+		{"<tag>", "0", ""},
+		{"yay", "1", "yay"},
+		{1221, "1", "1221"},
+		{1221, 2, "12211221"},
+		{template.HTML("<tag>"), "2", "<tag><tag>"},
+		{[]byte("<tag>"), 2, "<tag><tag>"},
+		// errors
+		{"", tstNoStringer{}, false},
+		{tstNoStringer{}, "", false},
+		{"hi", math.MaxInt16 + 1, false},
+	} {
+		errMsg := fmt.Sprintf("[%d] %v", i, test)
+
+		result, err := ns.Repeat(test.n, test.s)
 
 		if b, ok := test.expect.(bool); ok && !b {
 			require.Error(t, err, errMsg)