Skip to content

Commit

Permalink
Add try
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Apr 19, 2022
1 parent 41cc4e4 commit 1e71caa
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 2 deletions.
28 changes: 27 additions & 1 deletion tpl/internal/go_templates/texttemplate/hugo_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package template

import (
"context"
"fmt"
"io"
"reflect"

Expand Down Expand Up @@ -288,10 +289,28 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
panic("not reached")
}

type TryValue struct {
Value any
Err error
}

// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
// as the function itself.
func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) reflect.Value {
func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) (val reflect.Value) {

// Added for Hugo.
if name == "try" {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
val = reflect.ValueOf(TryValue{nil, err})
} else {
val = reflect.ValueOf(TryValue{nil, fmt.Errorf("%v", r)})
}
}
}()
}
if args != nil {
args = args[1:] // Zeroth arg is function name/node; not passed to function.
}
Expand Down Expand Up @@ -390,6 +409,13 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
s.at(node)
s.errorf("error calling %s: %w", name, err)
}

// Added for Hugo.
if name == "try" {
fmt.Println("GOT", v)
return reflect.ValueOf(TryValue{unwrap(v).Interface(), nil})
}

return unwrap(v)
}

Expand Down
2 changes: 1 addition & 1 deletion tpl/partials/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func init() {
},
)

// TODO(bep) we need the return to be a valid identifier, but
// TODO(bep) we need the return to be a valid identifiers, but
// should consider another way of adding it.
ns.AddMethodMapping(func() string { return "" },
[]string{"return"},
Expand Down
7 changes: 7 additions & 0 deletions tpl/safe/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ func init() {
[][2]string{},
)

ns.AddMethodMapping(func(v any) (any, error) {
return v, nil
},
[]string{"try"},
[][2]string{},
)

return ns
}

Expand Down
35 changes: 35 additions & 0 deletions tpl/templates/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,38 @@ post/doesnotexist.html: false
`)
}

func TestTry(t *testing.T) {
t.Parallel()

files := `
-- config.toml --
baseURL = 'http://example.com/'
-- layouts/index.html --
{{ $g := try ("hello = \"Hello Hugo\"" | transform.Unmarshal) }}
{{ with $g.Err }}
Err1: {{ . }}
{{ else }}
Value1: {{ $g.Value.hello | safeHTML }}|
{{ end }}
{{ $g := try ("hello != \"Hello Hugo\"" | transform.Unmarshal) }}
{{ with $g.Err }}
Err2: {{ . | safeHTML }}
{{ else }}
Value2: {{ $g.Value.hello | safeHTML }}|
{{ end }}
`

b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
},
).Build()

b.AssertFileContent("public/index.html",
"Value1: Hello Hugo|",
"Err2: template: index.html:7:52: executing \"index.html\" at <transform.Unmarshal>: error calling Unmarshal: unmarshal failed: toml: expected character =",
)
}

0 comments on commit 1e71caa

Please sign in to comment.