Skip to content

Commit

Permalink
Merge pull request #138 from thatguystone/implicit-exec
Browse files Browse the repository at this point in the history
Implicit *ExecutionContext arg, take 2
  • Loading branch information
flosch committed Aug 13, 2016
2 parents f3588f8 + 9c5c989 commit 22499f9
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 6 deletions.
35 changes: 35 additions & 0 deletions pongo2_test.go
Expand Up @@ -68,3 +68,38 @@ func (s *TestSuite) TestMisc(c *C) {
}
}, PanicMatches, `\[Error \(where: applyfilter\)\] Filter with name 'doesnotexist' not found.`)
}

func (s *TestSuite) TestImplicitExecCtx(c *C) {
tpl, err := pongo2.FromString("{{ ImplicitExec }}")
if err != nil {
c.Fatalf("Error in FromString: %v", err)
}

val := "a stringy thing"

res, err := tpl.Execute(pongo2.Context{
"Value": val,
"ImplicitExec": func(ctx *pongo2.ExecutionContext) string {
return ctx.Public["Value"].(string)
},
})

if err != nil {
c.Fatalf("Error executing template: %v", err)
}

c.Check(res, Equals, val)

// The implicit ctx should not be persisted from call-to-call
res, err = tpl.Execute(pongo2.Context{
"ImplicitExec": func() string {
return val
},
})

if err != nil {
c.Fatalf("Error executing template: %v", err)
}

c.Check(res, Equals, val)
}
29 changes: 23 additions & 6 deletions variable.go
Expand Up @@ -12,6 +12,11 @@ const (
varTypeIdent
)

var (
typeOfValuePtr = reflect.TypeOf(new(Value))
typeOfExecCtxPtr = reflect.TypeOf(new(ExecutionContext))
)

type variablePart struct {
typ int
s string
Expand Down Expand Up @@ -64,6 +69,8 @@ type nodeVariable struct {
expr IEvaluator
}

type executionCtxEval struct{}

func (v *nodeFilteredVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
value, err := v.Evaluate(ctx)
if err != nil {
Expand Down Expand Up @@ -196,6 +203,10 @@ func (nv *nodeVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *E
return nil
}

func (executionCtxEval) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
return AsValue(ctx), nil
}

func (vr *variableResolver) FilterApplied(name string) bool {
return false
}
Expand Down Expand Up @@ -300,7 +311,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
// If current is a reflect.ValueOf(pongo2.Value), then unpack it
// Happens in function calls (as a return value) or by injecting
// into the execution context (e.g. in a for-loop)
if current.Type() == reflect.TypeOf(&Value{}) {
if current.Type() == typeOfValuePtr {
tmpValue := current.Interface().(*Value)
current = tmpValue.val
isSafe = tmpValue.safe
Expand All @@ -321,12 +332,18 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
// Check for correct function syntax and types
// func(*Value, ...) *Value
t := current.Type()
currArgs := part.callingArgs

// If an implicit ExecCtx is needed
if t.NumIn() > 0 && t.In(0) == typeOfExecCtxPtr {
currArgs = append([]functionCallArgument{executionCtxEval{}}, currArgs...)
}

// Input arguments
if len(part.callingArgs) != t.NumIn() && !(len(part.callingArgs) >= t.NumIn()-1 && t.IsVariadic()) {
if len(currArgs) != t.NumIn() && !(len(currArgs) >= t.NumIn()-1 && t.IsVariadic()) {
return nil,
fmt.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
t.NumIn(), vr.String(), len(part.callingArgs))
t.NumIn(), vr.String(), len(currArgs))
}

// Output arguments
Expand All @@ -341,7 +358,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
isVariadic := t.IsVariadic()
var fnArg reflect.Type

for idx, arg := range part.callingArgs {
for idx, arg := range currArgs {
pv, err := arg.Evaluate(ctx)
if err != nil {
return nil, err
Expand All @@ -357,7 +374,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
fnArg = t.In(idx)
}

if fnArg != reflect.TypeOf(new(Value)) {
if fnArg != typeOfValuePtr {
// Function's argument is not a *pongo2.Value, then we have to check whether input argument is of the same type as the function's argument
if !isVariadic {
if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
Expand Down Expand Up @@ -390,7 +407,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
// Call it and get first return parameter back
rv := current.Call(parameters)[0]

if rv.Type() != reflect.TypeOf(new(Value)) {
if rv.Type() != typeOfValuePtr {
current = reflect.ValueOf(rv.Interface())
} else {
// Return the function call value
Expand Down

0 comments on commit 22499f9

Please sign in to comment.