tpl: Add strings.Repeat
authorDavid E. Wheeler <david@justatheory.com>
Sun, 3 Jun 2018 06:55:37 +0000 (02:55 -0400)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 3 Jun 2018 06:55:37 +0000 (09:55 +0300)
docs/content/en/functions/strings.Repeat.md [new file with mode: 0644]
docs/data/docs.json
tpl/strings/init.go
tpl/strings/strings.go
tpl/strings/strings_test.go

diff --git a/docs/content/en/functions/strings.Repeat.md b/docs/content/en/functions/strings.Repeat.md
new file mode 100644 (file)
index 0000000..8dcb8ea
--- /dev/null
@@ -0,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"
+```
index 2a7f727b7aeff1f2b00e13aaef2bd23088fb8824..4eddf8eae100da30613b07d6ce1525fb33920368 100644 (file)
             ]
           ]
         },
+        "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": [
index 54009b897bbcb58cb7c5341923341d820b7a44d7..883ce76d1e0f95283d69a01fd040da9fd0d6bff3 100644 (file)
@@ -158,6 +158,13 @@ func init() {
                        },
                )
 
+               ns.AddMethodMapping(ctx.Repeat,
+                       nil,
+                       [][2]string{
+                               {`{{ "yo" | strings.Repeat 4 }}`, `yoyoyoyo`},
+                       },
+               )
+
                ns.AddMethodMapping(ctx.ToUpper,
                        []string{"upper"},
                        [][2]string{
index 6d423391fe67f5638842e5bd31a63396239c20a0..796b8ff62edc2283b883c94b74dd9c614a063d7b 100644 (file)
@@ -17,6 +17,7 @@ import (
        "errors"
        "fmt"
        "html/template"
+       "math"
        _strings "strings"
        "unicode/utf8"
 
@@ -417,3 +418,23 @@ func (ns *Namespace) TrimSuffix(suffix, s interface{}) (string, error) {
 
        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
+}
index 91e71fd012e550b9640c0da559f61aa7e2b96ebc..bf19ad5621cbefa8d0212e771e9fdb01f2d95504 100644 (file)
@@ -16,6 +16,7 @@ package strings
 import (
        "fmt"
        "html/template"
+       "math"
        "testing"
 
        "github.com/gohugoio/hugo/deps"
@@ -709,3 +710,38 @@ func TestTrimSuffix(t *testing.T) {
                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)
+                       continue
+               }
+
+               require.NoError(t, err, errMsg)
+               assert.Equal(t, test.expect, result, errMsg)
+       }
+}