123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- package pongo2
- import (
- "fmt"
- "reflect"
- "strconv"
- "strings"
- )
- type Value struct {
- val reflect.Value
- safe bool // used to indicate whether a Value needs explicit escaping in the template
- }
- // Converts any given value to a pongo2.Value
- // Usually being used within own functions passed to a template
- // through a Context or within filter functions.
- //
- // Example:
- // AsValue("my string")
- func AsValue(i interface{}) *Value {
- return &Value{
- val: reflect.ValueOf(i),
- }
- }
- // Like AsValue, but does not apply the 'escape' filter.
- func AsSafeValue(i interface{}) *Value {
- return &Value{
- val: reflect.ValueOf(i),
- safe: true,
- }
- }
- func (v *Value) getResolvedValue() reflect.Value {
- if v.val.IsValid() && v.val.Kind() == reflect.Ptr {
- return v.val.Elem()
- }
- return v.val
- }
- // Checks whether the underlying value is a string
- func (v *Value) IsString() bool {
- return v.getResolvedValue().Kind() == reflect.String
- }
- // Checks whether the underlying value is a bool
- func (v *Value) IsBool() bool {
- return v.getResolvedValue().Kind() == reflect.Bool
- }
- // Checks whether the underlying value is a float
- func (v *Value) IsFloat() bool {
- return v.getResolvedValue().Kind() == reflect.Float32 ||
- v.getResolvedValue().Kind() == reflect.Float64
- }
- // Checks whether the underlying value is an integer
- func (v *Value) IsInteger() bool {
- return v.getResolvedValue().Kind() == reflect.Int ||
- v.getResolvedValue().Kind() == reflect.Int8 ||
- v.getResolvedValue().Kind() == reflect.Int16 ||
- v.getResolvedValue().Kind() == reflect.Int32 ||
- v.getResolvedValue().Kind() == reflect.Int64 ||
- v.getResolvedValue().Kind() == reflect.Uint ||
- v.getResolvedValue().Kind() == reflect.Uint8 ||
- v.getResolvedValue().Kind() == reflect.Uint16 ||
- v.getResolvedValue().Kind() == reflect.Uint32 ||
- v.getResolvedValue().Kind() == reflect.Uint64
- }
- // Checks whether the underlying value is either an integer
- // or a float.
- func (v *Value) IsNumber() bool {
- return v.IsInteger() || v.IsFloat()
- }
- // Checks whether the underlying value is NIL
- func (v *Value) IsNil() bool {
- //fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
- return !v.getResolvedValue().IsValid()
- }
- // Returns a string for the underlying value. If this value is not
- // of type string, pongo2 tries to convert it. Currently the following
- // types for underlying values are supported:
- //
- // 1. string
- // 2. int/uint (any size)
- // 3. float (any precision)
- // 4. bool
- // 5. time.Time
- // 6. String() will be called on the underlying value if provided
- //
- // NIL values will lead to an empty string. Unsupported types are leading
- // to their respective type name.
- func (v *Value) String() string {
- if v.IsNil() {
- return ""
- }
- switch v.getResolvedValue().Kind() {
- case reflect.String:
- return v.getResolvedValue().String()
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return strconv.FormatInt(v.getResolvedValue().Int(), 10)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return strconv.FormatUint(v.getResolvedValue().Uint(), 10)
- case reflect.Float32, reflect.Float64:
- return fmt.Sprintf("%f", v.getResolvedValue().Float())
- case reflect.Bool:
- if v.Bool() {
- return "True"
- } else {
- return "False"
- }
- case reflect.Struct:
- if t, ok := v.Interface().(fmt.Stringer); ok {
- return t.String()
- }
- }
- logf("Value.String() not implemented for type: %s\n", v.getResolvedValue().Kind().String())
- return v.getResolvedValue().String()
- }
- // Returns the underlying value as an integer (converts the underlying
- // value, if necessary). If it's not possible to convert the underlying value,
- // it will return 0.
- func (v *Value) Integer() int {
- switch v.getResolvedValue().Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return int(v.getResolvedValue().Int())
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return int(v.getResolvedValue().Uint())
- case reflect.Float32, reflect.Float64:
- return int(v.getResolvedValue().Float())
- case reflect.String:
- // Try to convert from string to int (base 10)
- f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
- if err != nil {
- return 0
- }
- return int(f)
- default:
- logf("Value.Integer() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return 0
- }
- }
- // Returns the underlying value as a float (converts the underlying
- // value, if necessary). If it's not possible to convert the underlying value,
- // it will return 0.0.
- func (v *Value) Float() float64 {
- switch v.getResolvedValue().Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return float64(v.getResolvedValue().Int())
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return float64(v.getResolvedValue().Uint())
- case reflect.Float32, reflect.Float64:
- return v.getResolvedValue().Float()
- case reflect.String:
- // Try to convert from string to float64 (base 10)
- f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
- if err != nil {
- return 0.0
- }
- return f
- default:
- logf("Value.Float() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return 0.0
- }
- }
- // Returns the underlying value as bool. If the value is not bool, false
- // will always be returned. If you're looking for true/false-evaluation of the
- // underlying value, have a look on the IsTrue()-function.
- func (v *Value) Bool() bool {
- switch v.getResolvedValue().Kind() {
- case reflect.Bool:
- return v.getResolvedValue().Bool()
- default:
- logf("Value.Bool() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return false
- }
- }
- // Tries to evaluate the underlying value the Pythonic-way:
- //
- // Returns TRUE in one the following cases:
- //
- // * int != 0
- // * uint != 0
- // * float != 0.0
- // * len(array/chan/map/slice/string) > 0
- // * bool == true
- // * underlying value is a struct
- //
- // Otherwise returns always FALSE.
- func (v *Value) IsTrue() bool {
- switch v.getResolvedValue().Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return v.getResolvedValue().Int() != 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return v.getResolvedValue().Uint() != 0
- case reflect.Float32, reflect.Float64:
- return v.getResolvedValue().Float() != 0
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
- return v.getResolvedValue().Len() > 0
- case reflect.Bool:
- return v.getResolvedValue().Bool()
- case reflect.Struct:
- return true // struct instance is always true
- default:
- logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return false
- }
- }
- // Tries to negate the underlying value. It's mainly used for
- // the NOT-operator and in conjunction with a call to
- // return_value.IsTrue() afterwards.
- //
- // Example:
- // AsValue(1).Negate().IsTrue() == false
- func (v *Value) Negate() *Value {
- switch v.getResolvedValue().Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
- reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- if v.Integer() != 0 {
- return AsValue(0)
- } else {
- return AsValue(1)
- }
- case reflect.Float32, reflect.Float64:
- if v.Float() != 0.0 {
- return AsValue(float64(0.0))
- } else {
- return AsValue(float64(1.1))
- }
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
- return AsValue(v.getResolvedValue().Len() == 0)
- case reflect.Bool:
- return AsValue(!v.getResolvedValue().Bool())
- default:
- logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return AsValue(true)
- }
- }
- // Returns the length for an array, chan, map, slice or string.
- // Otherwise it will return 0.
- func (v *Value) Len() int {
- switch v.getResolvedValue().Kind() {
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
- return v.getResolvedValue().Len()
- case reflect.String:
- runes := []rune(v.getResolvedValue().String())
- return len(runes)
- default:
- logf("Value.Len() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return 0
- }
- }
- // Slices an array, slice or string. Otherwise it will
- // return an empty []int.
- func (v *Value) Slice(i, j int) *Value {
- switch v.getResolvedValue().Kind() {
- case reflect.Array, reflect.Slice:
- return AsValue(v.getResolvedValue().Slice(i, j).Interface())
- case reflect.String:
- runes := []rune(v.getResolvedValue().String())
- return AsValue(string(runes[i:j]))
- default:
- logf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return AsValue([]int{})
- }
- }
- // Get the i-th item of an array, slice or string. Otherwise
- // it will return NIL.
- func (v *Value) Index(i int) *Value {
- switch v.getResolvedValue().Kind() {
- case reflect.Array, reflect.Slice:
- if i >= v.Len() {
- return AsValue(nil)
- }
- return AsValue(v.getResolvedValue().Index(i).Interface())
- case reflect.String:
- //return AsValue(v.getResolvedValue().Slice(i, i+1).Interface())
- s := v.getResolvedValue().String()
- runes := []rune(s)
- if i < len(runes) {
- return AsValue(string(runes[i]))
- }
- return AsValue("")
- default:
- logf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return AsValue([]int{})
- }
- }
- // Checks whether the underlying value (which must be of type struct, map,
- // string, array or slice) contains of another Value (e. g. used to check
- // whether a struct contains of a specific field or a map contains a specific key).
- //
- // Example:
- // AsValue("Hello, World!").Contains(AsValue("World")) == true
- func (v *Value) Contains(other *Value) bool {
- switch v.getResolvedValue().Kind() {
- case reflect.Struct:
- field_value := v.getResolvedValue().FieldByName(other.String())
- return field_value.IsValid()
- case reflect.Map:
- var map_value reflect.Value
- switch other.Interface().(type) {
- case int:
- map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
- case string:
- map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
- default:
- logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
- return false
- }
- return map_value.IsValid()
- case reflect.String:
- return strings.Contains(v.getResolvedValue().String(), other.String())
- // TODO: reflect.Array, reflect.Slice
- default:
- logf("Value.Contains() not available for type: %s\n", v.getResolvedValue().Kind().String())
- return false
- }
- }
- // Checks whether the underlying value is of type array, slice or string.
- // You normally would use CanSlice() before using the Slice() operation.
- func (v *Value) CanSlice() bool {
- switch v.getResolvedValue().Kind() {
- case reflect.Array, reflect.Slice, reflect.String:
- return true
- }
- return false
- }
- // Iterates over a map, array, slice or a string. It calls the
- // function's first argument for every value with the following arguments:
- //
- // idx current 0-index
- // count total amount of items
- // key *Value for the key or item
- // value *Value (only for maps, the respective value for a specific key)
- //
- // If the underlying value has no items or is not one of the types above,
- // the empty function (function's second argument) will be called.
- func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
- v.IterateOrder(fn, empty, false)
- }
- // Like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
- // not affect the iteration through a map because maps don't have any particular order.
- func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool) {
- switch v.getResolvedValue().Kind() {
- case reflect.Map:
- // Reverse not needed for maps, since they are not ordered
- keys := v.getResolvedValue().MapKeys()
- keyLen := len(keys)
- for idx, key := range keys {
- value := v.getResolvedValue().MapIndex(key)
- if !fn(idx, keyLen, &Value{val: key}, &Value{val: value}) {
- return
- }
- }
- if keyLen == 0 {
- empty()
- }
- return // done
- case reflect.Array, reflect.Slice:
- itemCount := v.getResolvedValue().Len()
- if itemCount > 0 {
- if reverse {
- for i := itemCount - 1; i >= 0; i-- {
- if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
- return
- }
- }
- } else {
- for i := 0; i < itemCount; i++ {
- if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
- return
- }
- }
- }
- } else {
- empty()
- }
- return // done
- case reflect.String:
- // TODO: Not utf8-compatible (utf8-decoding neccessary)
- charCount := v.getResolvedValue().Len()
- if charCount > 0 {
- if reverse {
- for i := charCount - 1; i >= 0; i-- {
- if !fn(i, charCount, &Value{val: v.getResolvedValue().Slice(i, i+1)}, nil) {
- return
- }
- }
- } else {
- for i := 0; i < charCount; i++ {
- if !fn(i, charCount, &Value{val: v.getResolvedValue().Slice(i, i+1)}, nil) {
- return
- }
- }
- }
- } else {
- empty()
- }
- return // done
- default:
- logf("Value.Iterate() not available for type: %s\n", v.getResolvedValue().Kind().String())
- }
- empty()
- }
- // Gives you access to the underlying value.
- func (v *Value) Interface() interface{} {
- if v.val.IsValid() {
- return v.val.Interface()
- }
- return nil
- }
- // Checks whether two values are containing the same value or object.
- func (v *Value) EqualValueTo(other *Value) bool {
- return v.Interface() == other.Interface()
- }
|