Search code examples
gotemplatespongo2

Golang pongo2 filter returns incorrect value


I created a pongo2 filter which should return Absolute value of the parameter passed in to the filter. However, the filter only returns correct answer if I pass the value as a parameter. But if I pass the value directly it returns incorrect value.

My question is why does it not return correct result if I pass the value directly instead of as a parameter?

package main

import (
    "fmt"
    "math"
        "github.com/flosch/pongo2"
    "log"
)

func init() {
    pongo2.RegisterFilter("abs", func(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
        if in.IsString() {
            return pongo2.AsValue(math.Abs(in.Float())), nil
        }
        return pongo2.AsValue(math.Abs(in.Float())), nil
    })
}

func correctWay() {
    tpl, err := pongo2.FromString("Hello {{ val|abs }}!")
        if err != nil {
            log.Fatal(err)
        }
    
        // Now you can render the template with the given
        // pongo2.Context how often you want to.
        out, err := tpl.Execute(pongo2.Context{"val": -5})
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println(out)
}

func incorrectWay() {
    tpl, err := pongo2.FromString("Hello {{ -5|abs }}!")
        if err != nil {
            log.Fatal(err)
        }
    
        // Now you can render the template with the given
        // pongo2.Context how often you want to.
        out, err := tpl.Execute(pongo2.Context{})
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println(out)
}


func main() {
    correctWay()
    incorrectWay()
}

Solution

  • I think the easiest option is to pass it as a string.

    // This works:
    tpl, err := pongo2.FromString("Hello {{ '-5'|abs }}!")
    // prints Hello 5.000000!
    

    I did a bit of experimenting, originally I thought it's because of how Go handles the minus sign in templates, but I don't think this is the case. I can't work out what pongo is doing, I am fairly certain if you pass in -5 only the 5 is passed to the function you register (add fmt.Println(in.Float()) to the closure), which then is negated when it's outputted by Go. This could be a bug 🤷‍♂️. Either way, it works with a string.