-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfunc.go
More file actions
255 lines (224 loc) · 6.41 KB
/
func.go
File metadata and controls
255 lines (224 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package gator
import (
"errors"
"reflect"
"strconv"
"github.com/ShaleApps/gator/Godeps/_workspace/src/github.com/onsi/gomega/matchers"
)
const (
regexEmail = `^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`
regexHexColor = `^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$`
regexURL = `^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$`
regexIP = `^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`
regexNum = `^[1-9]\d*(\.\d+)?$`
regexAlpha = `^[a-zA-Z]*$`
)
// Func is a validation function that returns an error if v is invalid.
type Func func(name string, v interface{}) error
// Matches returns a Func that validates against the given regex.
func Matches(regex string) Func {
m := &matchers.MatchRegexpMatcher{Regexp: regex}
return match(m)
}
// Nonzero returns a Func that validates its value is non-zero.
// http://golang.org/pkg/reflect/#Zero
func Nonzero() Func {
return func(name string, v interface{}) error {
m := &matchers.BeZeroMatcher{}
zero, _ := m.Match(v)
if zero {
return formatError(name)
}
return nil
}
}
// Eq returns a Func that validates its value is equal to v. Eq uses a numerical
// comparison for built-in number types. For example 1.0 of type float64 would equal
// 1 of type int. All other types are compared using reflect.DeepEquals except when
// the value is a built-in number type and v is a string. Strings are converted into
// numbers if parsable to support struct tags.
func Eq(v interface{}) Func {
return func(k string, ov interface{}) error {
switch ov.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
switch vt := v.(type) {
case string:
n, err := strconv.ParseFloat(vt, 64)
if err != nil {
return formatError(k)
}
f := numericalMatch("==", n)
return f(k, ov)
}
f := numericalMatch("==", v)
return f(k, ov)
}
if !reflect.DeepEqual(v, ov) {
return formatError(k)
}
return nil
}
}
// Email returns a Func that validates its value is an email address.
func Email() Func {
return Matches(regexEmail)
}
// HexColor returns a Func that validates its value is a hexidecimal number prefixed by a hash.
// HTML standard link: http://www.w3.org/TR/REC-html40/types.html#h-6.5
func HexColor() Func {
return Matches(regexHexColor)
}
// URL returns a Func that validates its value is a URL.
func URL() Func {
return Matches(regexURL)
}
// IP returns a Func that validates its value is an IP address.
func IP() Func {
return Matches(regexIP)
}
// Alpha returns a Func that validates its value contains only letters.
func Alpha() Func {
return Matches(regexAlpha)
}
// Num returns a Func that validates its value contains only numbers.
func Num() Func {
return Matches(regexNum)
}
// AlphaNum returns a Func that validates its value contains both numbers and letters.
func AlphaNum() Func {
return combineFuncs(Matches("[a-zA-Z]+"), Matches("[0-9]+"))
}
// Gt returns a Func that validates its value is a number greater than v.
func Gt(v interface{}) Func {
return numericalMatch(">", v)
}
// Gte returns a Func that validates its value is a number greater than or equal to v.
func Gte(v interface{}) Func {
return numericalMatch(">=", v)
}
// Lt returns a Func that validates its value is a number less than v.
func Lt(v interface{}) Func {
return numericalMatch("<", v)
}
// Lte returns a Func that validates its value is a number less than or equal to v.
func Lte(v interface{}) Func {
return numericalMatch("<=", v)
}
// Lat returns a Func that validates its value is a decimal between 90 and -90.
func Lat() Func {
return combineFuncs(
numericalMatch("<=", 90.0),
numericalMatch(">=", -90.0))
}
// Lon returns a Func that validates its value is a decimal between 180 and -180.
func Lon() Func {
return combineFuncs(
numericalMatch("<=", 180.0),
numericalMatch(">=", -180.0))
}
// In returns a Func that validates its value is in the inputed list. Comparisons
// use reflect.DeepEqual.
func In(list []interface{}) Func {
return func(k string, v interface{}) error {
in := false
for _, e := range list {
in = in || reflect.DeepEqual(e, v)
}
if !in {
return formatError(k)
}
return nil
}
}
// NotIn returns a Func that validates its value is not in the inputed list. Comparisons
// use reflect.DeepEqual.
func NotIn(list []interface{}) Func {
return func(k string, v interface{}) error {
for _, e := range list {
if reflect.DeepEqual(e, v) {
return formatError(k)
}
}
return nil
}
}
// Len returns a Func that validates its value's length is equal to l.
func Len(l int) Func {
return func(k string, v interface{}) error {
length, ok := lengthOf(v)
if !ok || length != l {
return formatError(k)
}
return nil
}
}
// MinLen returns a Func that validates its value's length is greater than or equal to l.
func MinLen(l int) Func {
return func(k string, v interface{}) error {
length, ok := lengthOf(v)
if !ok || length < l {
return formatError(k)
}
return nil
}
}
// MaxLen returns a Func that validates its value's length is less than or equal to l.
func MaxLen(l int) Func {
return func(k string, v interface{}) error {
length, ok := lengthOf(v)
if !ok || length > l {
return formatError(k)
}
return nil
}
}
// Each returns a Func that validates the list of functions for each element in an array or slice.
func Each(funcs ...Func) Func {
return func(k string, v interface{}) error {
if !isArrayOrSlice(v) {
return formatError(k)
}
value := reflect.ValueOf(v)
for i := 0; i < value.Len(); i++ {
iFace := value.Index(i).Interface()
for _, f := range funcs {
if err := f(k, iFace); err != nil {
return formatError(k)
}
}
}
return nil
}
}
type matcher interface {
Match(actual interface{}) (success bool, err error)
}
func numericalMatch(comparator string, v interface{}) Func {
m := &matchers.BeNumericallyMatcher{
Comparator: comparator,
CompareTo: []interface{}{v},
}
return match(m)
}
func match(m matcher) Func {
return func(name string, v interface{}) error {
matches, _ := m.Match(v)
if !matches {
return formatError(name)
}
return nil
}
}
func combineFuncs(funcs ...Func) Func {
return func(name string, v interface{}) error {
for _, f := range funcs {
if err := f(name, v); err != nil {
return err
}
}
return nil
}
}
func formatError(name string) error {
return errors.New(name + " did not pass validation.")
}