`,
)
})
+}
- c.Run("Zero argument", func(c *qt.C) {
- b := newBuilder(c)
-
- b.WithTemplatesAdded(
- "index.html", `
-Test Partials With Return Values:
-
-add42: fail: {{ partial "add42.tpl" 0 }}
+// Issue 7528
+func TestPartialWithZeroedArgs(t *testing.T) {
-`,
- )
+ b := newTestSitesBuilder(t)
+ b.WithTemplatesAdded("index.html",
+ `
+X{{ partial "retval" dict }}X
+X{{ partial "retval" slice }}X
+X{{ partial "retval" "" }}X
+X{{ partial "retval" false }}X
+X{{ partial "retval" 0 }}X
+{{ define "partials/retval" }}
+ {{ return 123 }}
+{{ end }}`)
+
+ b.WithContentAdded("p.md", ``)
+ b.Build(BuildCfg{})
+ b.AssertFileContent("public/index.html",
+ `
+X123X
+X123X
+X123X
+X123X
+X123X
+`)
- e := b.CreateSites().BuildE(BuildCfg{})
- b.Assert(e, qt.Not(qt.IsNil))
- })
}
func TestPartialCached(t *testing.T) {
"strings"
"sync"
- "github.com/gohugoio/hugo/common/hreflect"
texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
"github.com/gohugoio/hugo/helpers"
var w io.Writer
if info.HasReturn {
- if !hreflect.IsTruthful(context) {
- // TODO(bep) we need to fix this, but it is non-trivial.
- return nil, errors.New("partial that returns a value needs a non-zero argument.")
- }
// Wrap the context sent to the template to capture the return value.
// Note that the template is rewritten to make sure that the dot (".")
// and the $ variable points to Arg.
}
const (
- partialReturnWrapperTempl = `{{ $_hugo_dot := $ }}{{ $ := .Arg }}{{ with .Arg }}{{ $_hugo_dot.Set ("PLACEHOLDER") }}{{ end }}`
+ // We parse this template and modify the nodes in order to assign
+ // the return value of a partial to a contextWrapper via Set. We use
+ // "range" over a one-element slice so we can shift dot to the
+ // partial's argument, Arg, while allowing Arg to be falsy.
+ partialReturnWrapperTempl = `{{ $_hugo_dot := $ }}{{ $ := .Arg }}{{ range (slice .Arg) }}{{ $_hugo_dot.Set ("PLACEHOLDER") }}{{ end }}`
)
var partialReturnWrapper *parse.ListNode
partialReturnWrapper = templ.Tree.Root
}
+// wrapInPartialReturnWrapper copies and modifies the parsed nodes of a
+// predefined partial return wrapper to insert those of a user-defined partial.
func (c *templateContext) wrapInPartialReturnWrapper(n *parse.ListNode) *parse.ListNode {
wrapper := partialReturnWrapper.CopyList()
- withNode := wrapper.Nodes[2].(*parse.WithNode)
- retn := withNode.List.Nodes[0]
+ rangeNode := wrapper.Nodes[2].(*parse.RangeNode)
+ retn := rangeNode.List.Nodes[0]
setCmd := retn.(*parse.ActionNode).Pipe.Cmds[0]
setPipe := setCmd.Args[1].(*parse.PipeNode)
// Replace PLACEHOLDER with the real return value.
// Note that this is a PipeNode, so it will be wrapped in parens.
setPipe.Cmds = []*parse.CommandNode{c.returnNode}
- withNode.List.Nodes = append(n.Nodes, retn)
+ rangeNode.List.Nodes = append(n.Nodes, retn)
return wrapper
}