Skip to content

Commit 73a8fa1

Browse files
committed
Alter the behavior of equal util method along with Contains, IndexOf & LastIndexOf functions
1 parent d1bdc9c commit 73a8fa1

File tree

4 files changed

+74
-9
lines changed

4 files changed

+74
-9
lines changed

predicate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func predicatesImpl(value interface{}, wantedAnswer bool, predicates interface{}
2020
}
2121

2222
funcType := funcValue.Type()
23-
if funcType.NumIn() != 1 || funcType.NumOut() != 1 || funcType.Out(0).Kind() != reflect.Bool {
23+
if !IsPredicate(funcValue.Interface()) {
2424
panic("Predicate function must have 1 parameter and must return boolean")
2525
}
2626

presence.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ func IndexOf(in interface{}, elem interface{}) int {
118118
}
119119

120120
if inType.Kind() == reflect.Slice {
121+
equalTo := equal(elem)
121122
for i := 0; i < inValue.Len(); i++ {
122-
if equal(inValue.Index(i).Interface(), elem) {
123+
if equalTo(reflect.Value{}, inValue.Index(i)) {
123124
return i
124125
}
125126
}
@@ -144,8 +145,9 @@ func LastIndexOf(in interface{}, elem interface{}) int {
144145
if inType.Kind() == reflect.Slice {
145146
length := inValue.Len()
146147

148+
equalTo := equal(elem)
147149
for i := length - 1; i >= 0; i-- {
148-
if equal(inValue.Index(i).Interface(), elem) {
150+
if equalTo(reflect.Value{}, inValue.Index(i)) {
149151
return i
150152
}
151153
}
@@ -164,14 +166,16 @@ func Contains(in interface{}, elem interface{}) bool {
164166
case reflect.String:
165167
return strings.Contains(inValue.String(), elemValue.String())
166168
case reflect.Map:
169+
equalTo := equal(elem, true)
167170
for _, key := range inValue.MapKeys() {
168-
if equal(key.Interface(), elem) {
171+
if equalTo(key, inValue.MapIndex(key)) {
169172
return true
170173
}
171174
}
172175
case reflect.Slice, reflect.Array:
176+
equalTo := equal(elem)
173177
for i := 0; i < inValue.Len(); i++ {
174-
if equal(inValue.Index(i).Interface(), elem) {
178+
if equalTo(reflect.Value{}, inValue.Index(i)) {
175179
return true
176180
}
177181
}

presence_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ func TestContains(t *testing.T) {
5454

5555
is.True(Contains(mapping, 1))
5656
is.False(Contains(mapping, 2))
57+
58+
is.False(Contains(mapping, func (key int, val *Foo) bool {
59+
return key == 4
60+
}))
61+
is.True(Contains(mapping, func (key int, val *Foo) bool {
62+
return key == 1
63+
}))
64+
65+
is.False(Contains(mapping, func (_ int, val *Foo) bool {
66+
return val.FirstName == "NotPresent"
67+
}))
68+
is.True(Contains(mapping, func (_ int, val *Foo) bool {
69+
return val.FirstName == "Harald"
70+
}))
5771
}
5872

5973
func TestEvery(t *testing.T) {
@@ -117,6 +131,9 @@ func TestIndexOf(t *testing.T) {
117131
is := assert.New(t)
118132

119133
is.Equal(IndexOf([]string{"foo", "bar"}, "bar"), 1)
134+
is.Equal(IndexOf([]string{"foo", "bar"}, func (value string) bool {
135+
return value == "bar"
136+
}), 1)
120137

121138
is.Equal(IndexOf(results, f), 0)
122139
is.Equal(IndexOf(results, b), -1)
@@ -126,6 +143,9 @@ func TestLastIndexOf(t *testing.T) {
126143
is := assert.New(t)
127144

128145
is.Equal(LastIndexOf([]string{"foo", "bar", "bar"}, "bar"), 2)
146+
is.Equal(LastIndexOf([]string{"foo", "bar", "bar"}, func (value string) bool {
147+
return value == "bar"
148+
}), 2)
129149
is.Equal(LastIndexOf([]int{1, 2, 2, 3}, 2), 2)
130150
is.Equal(LastIndexOf([]int{1, 2, 2, 3}, 4), -1)
131151
}

utils.go

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,57 @@
11
package funk
22

33
import (
4+
"fmt"
45
"reflect"
56
)
67

7-
func equal(expected, actual interface{}) bool {
8-
if expected == nil || actual == nil {
9-
return expected == actual
8+
func equal(expectedOrPredicate interface{}, optionalIsMap ...bool) func(keyValueIfMap, actualValue reflect.Value) bool {
9+
isMap := append(optionalIsMap, false)[0]
10+
11+
if IsFunction(expectedOrPredicate) {
12+
inTypes := []reflect.Type{nil}; if isMap {
13+
inTypes = append(inTypes, nil)
14+
}
15+
16+
if !IsPredicate(expectedOrPredicate, inTypes...) {
17+
panic(fmt.Sprintf("Predicate function must have %d parameter and must return boolean", len(inTypes)))
18+
}
19+
20+
predicateValue := reflect.ValueOf(expectedOrPredicate)
21+
22+
return func(keyValueIfMap, actualValue reflect.Value) bool {
23+
24+
if isMap && !keyValueIfMap.Type().ConvertibleTo(predicateValue.Type().In(0)) {
25+
panic("Given key is not compatible with type of parameter for the predicate.")
26+
}
27+
28+
if (isMap && !actualValue.Type().ConvertibleTo(predicateValue.Type().In(1))) ||
29+
(!isMap && !actualValue.Type().ConvertibleTo(predicateValue.Type().In(0))) {
30+
panic("Given value is not compatible with type of parameter for the predicate.")
31+
}
32+
33+
args := []reflect.Value{actualValue}
34+
if isMap {
35+
args = append([]reflect.Value{keyValueIfMap}, args...)
36+
}
37+
38+
return predicateValue.Call(args)[0].Bool()
39+
}
1040
}
1141

12-
return reflect.DeepEqual(expected, actual)
42+
expected := expectedOrPredicate
43+
44+
return func(keyValueIfMap, actualValue reflect.Value) bool {
45+
if isMap {
46+
actualValue = keyValueIfMap
47+
}
48+
49+
if expected == nil || actualValue.IsZero() {
50+
return actualValue.Interface() == expected
51+
}
1352

53+
return reflect.DeepEqual(actualValue.Interface(), expected)
54+
}
1455
}
1556

1657
func sliceElem(rtype reflect.Type) reflect.Type {

0 commit comments

Comments
 (0)