Skip to content

Commit

Permalink
Merge branch 'eqenhance' of github.com:Shaban/revel into Shaban-eqenh…
Browse files Browse the repository at this point in the history
…ance
  • Loading branch information
robfig committed Mar 23, 2013
2 parents f42816a + 89dd7da commit d2ac37b
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 2 deletions.
46 changes: 44 additions & 2 deletions template.go
Expand Up @@ -40,7 +40,7 @@ var (
// The functions available for use in the templates.
TemplateFuncs = map[string]interface{}{
"url": ReverseUrl,
"eq": func(a, b interface{}) bool { return a == b },
"eq": tplEq,
"set": func(renderArgs map[string]interface{}, key string, value interface{}) template.HTML {
renderArgs[key] = value
return template.HTML("")
Expand Down Expand Up @@ -70,7 +70,6 @@ var (
return template.HTML(fmt.Sprintf(`<input type="radio" name="%s" value="%s"%s>`,
html.EscapeString(f.Name), html.EscapeString(val), checked))
},

// Pads the given string with &nbsp;'s up to the given width.
"pad": func(str string, width int) template.HTML {
if len(str) >= width {
Expand Down Expand Up @@ -358,3 +357,46 @@ func ReverseUrl(args ...interface{}) string {

return MainRouter.Reverse(args[0].(string), argsByName).Url
}

// tplEq is a helper for comparing values of equivalent data types.
// It treats all int types as int64 all float types as float64 and all uint types as uint64.
// Also strings and byte slices are treated as being equivalent types.
// Conceptually similar values like 'a' vs "a" and 52 vs "52" are not treated as equivalent types.
// It can also handle arrays, slices, maps, and fields of structs even recursive types.
// Functions are reported equal if both are nil.
// Don't use it to compare pointer types, it will compare the underlying types - not the memory address.
// If you wish to compare two instances of the same type compare fields under given type holding a unique value.
func tplEq(a, b interface{}) bool {
if reflect.TypeOf(a) == reflect.TypeOf(b) {
return reflect.DeepEqual(a, b)
}
switch a.(type) {
case int, int8, int16, int32, int64:
switch b.(type) {
case int, int8, int16, int32, int64:
return reflect.ValueOf(a).Int() == reflect.ValueOf(b).Int()
}
case uint, uint8, uint16, uint32, uint64:
switch b.(type) {
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(a).Uint() == reflect.ValueOf(b).Uint()
}
case float32, float64:
switch b.(type) {
case float32, float64:
return reflect.ValueOf(a).Float() == reflect.ValueOf(b).Float()
}
case string:
switch b.(type) {
case []byte:
return a.(string) == string(b.([]byte))
}

case []byte:
switch b.(type) {
case string:
return b.(string) == string(a.([]byte))
}
}
return false
}
68 changes: 68 additions & 0 deletions template_test.go
@@ -0,0 +1,68 @@
package revel

import (
"reflect"
"testing"
)

func TestTplEq(t *testing.T) {
type list []interface{}
type testStruct struct{}
type testStruct2 struct{}
i, i2 := 8, 9
s, s2 := "@朕µ\n\tüöäß", "@朕µ\n\tüöäss"
slice, slice2 := []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}
slice3, slice4 := []int{5, 4, 3, 2, 1}, []int{5, 4, 3, 2, 1}

tm := map[string]list{
"slices": list{slice, slice2},
"slices2": list{slice3, slice4},
"types": list{new(testStruct), new(testStruct)},
"types2": {new(testStruct2), new(testStruct2)},
"ints": {int(i), int8(i), int16(i), int32(i), int64(i)},
"ints2": {int(i2), int8(i2), int16(i2), int32(i2), int64(i2)},
"uints": {uint(i), uint8(i), uint16(i), uint32(i), uint64(i)},
"uints2": {uint(i2), uint8(i2), uint16(i2), uint32(i2), uint64(i2)},
"floats": {float32(i), float64(i)},
"floats2": {float32(i2), float64(i2)},
"strings": {[]byte(s), s},
"strings2": {[]byte(s2), s2},
}

testRow := func(row, row2 list, expected bool) {
for _, a := range row {
for _, b := range row2 {
ok := tplEq(a, b)
if ok != expected {
ak := reflect.TypeOf(a).Kind()
bk := reflect.TypeOf(b).Kind()
t.Errorf("eq(%s=%v,%s=%v) want %t got %t", ak, a, bk, b, expected, ok)
}
}
}
}

testRow(tm["slices"], tm["slices"], true)
testRow(tm["slices"], tm["slices2"], false)
testRow(tm["slices2"], tm["slices"], false)

testRow(tm["types"], tm["types"], true)
testRow(tm["types2"], tm["types"], false)
testRow(tm["types"], tm["types2"], false)

testRow(tm["ints"], tm["ints"], true)
testRow(tm["ints"], tm["ints2"], false)
testRow(tm["ints2"], tm["ints"], false)

testRow(tm["uints"], tm["uints"], true)
testRow(tm["uints2"], tm["uints"], false)
testRow(tm["uints"], tm["uints2"], false)

testRow(tm["floats"], tm["floats"], true)
testRow(tm["floats2"], tm["floats"], false)
testRow(tm["floats"], tm["floats2"], false)

testRow(tm["strings"], tm["strings"], true)
testRow(tm["strings2"], tm["strings"], false)
testRow(tm["strings"], tm["strings2"], false)
}

0 comments on commit d2ac37b

Please sign in to comment.