add funcmap
Showing
5 changed files
with
128 additions
and
33 deletions
| ... | @@ -3,6 +3,8 @@ package validation | ... | @@ -3,6 +3,8 @@ package validation |
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "reflect" | 5 | "reflect" |
| 6 | "regexp" | ||
| 7 | "strconv" | ||
| 6 | "strings" | 8 | "strings" |
| 7 | ) | 9 | ) |
| 8 | 10 | ||
| ... | @@ -13,7 +15,7 @@ const ( | ... | @@ -13,7 +15,7 @@ const ( |
| 13 | var ( | 15 | var ( |
| 14 | // key: function name | 16 | // key: function name |
| 15 | // value: the number of parameters | 17 | // value: the number of parameters |
| 16 | funcs = make(map[string]int) | 18 | funcs = make(Funcs) |
| 17 | 19 | ||
| 18 | // doesn't belong to validation functions | 20 | // doesn't belong to validation functions |
| 19 | unFuncs = map[string]bool{ | 21 | unFuncs = map[string]bool{ |
| ... | @@ -33,7 +35,7 @@ func init() { | ... | @@ -33,7 +35,7 @@ func init() { |
| 33 | for i := 0; i < t.NumMethod(); i++ { | 35 | for i := 0; i < t.NumMethod(); i++ { |
| 34 | m := t.Method(i) | 36 | m := t.Method(i) |
| 35 | if !unFuncs[m.Name] { | 37 | if !unFuncs[m.Name] { |
| 36 | funcs[m.Name] = m.Type.NumIn() - 3 | 38 | funcs[m.Name] = m.Func |
| 37 | } | 39 | } |
| 38 | } | 40 | } |
| 39 | } | 41 | } |
| ... | @@ -43,6 +45,25 @@ type ValidFunc struct { | ... | @@ -43,6 +45,25 @@ type ValidFunc struct { |
| 43 | Params []interface{} | 45 | Params []interface{} |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 48 | type Funcs map[string]reflect.Value | ||
| 49 | |||
| 50 | func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { | ||
| 51 | if _, ok := f[name]; !ok { | ||
| 52 | err = fmt.Errorf("%s does not exist", name) | ||
| 53 | return | ||
| 54 | } | ||
| 55 | if len(params) != f[name].Type().NumIn() { | ||
| 56 | err = fmt.Errorf("The number of params is not adapted") | ||
| 57 | return | ||
| 58 | } | ||
| 59 | in := make([]reflect.Value, len(params)) | ||
| 60 | for k, param := range params { | ||
| 61 | in[k] = reflect.ValueOf(param) | ||
| 62 | } | ||
| 63 | result = f[name].Call(in) | ||
| 64 | return | ||
| 65 | } | ||
| 66 | |||
| 46 | func isStruct(t reflect.Type) bool { | 67 | func isStruct(t reflect.Type) bool { |
| 47 | return t.Kind() == reflect.Struct | 68 | return t.Kind() == reflect.Struct |
| 48 | } | 69 | } |
| ... | @@ -110,22 +131,53 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { | ... | @@ -110,22 +131,53 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { |
| 110 | return | 131 | return |
| 111 | } | 132 | } |
| 112 | 133 | ||
| 113 | v = ValidFunc{name, trim(params)} | 134 | tParams, err := trim(name, params) |
| 135 | if err != nil { | ||
| 136 | return | ||
| 137 | } | ||
| 138 | v = ValidFunc{name, tParams} | ||
| 114 | return | 139 | return |
| 115 | } | 140 | } |
| 116 | 141 | ||
| 117 | func numIn(name string) (num int, err error) { | 142 | func numIn(name string) (num int, err error) { |
| 118 | num, ok := funcs[name] | 143 | fn, ok := funcs[name] |
| 119 | if !ok { | 144 | if !ok { |
| 120 | err = fmt.Errorf("doesn't exsits %s valid function", name) | 145 | err = fmt.Errorf("doesn't exsits %s valid function", name) |
| 146 | return | ||
| 121 | } | 147 | } |
| 148 | num = fn.Type().NumIn() - 3 | ||
| 122 | return | 149 | return |
| 123 | } | 150 | } |
| 124 | 151 | ||
| 125 | func trim(s []string) []interface{} { | 152 | func trim(name string, s []string) (ts []interface{}, err error) { |
| 126 | ts := make([]interface{}, len(s)) | 153 | ts = make([]interface{}, len(s)) |
| 154 | fn, ok := funcs[name] | ||
| 155 | if !ok { | ||
| 156 | err = fmt.Errorf("doesn't exsits %s valid function", name) | ||
| 157 | return | ||
| 158 | } | ||
| 127 | for i := 0; i < len(s); i++ { | 159 | for i := 0; i < len(s); i++ { |
| 128 | ts[i] = strings.TrimSpace(s[i]) | 160 | var param interface{} |
| 161 | if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { | ||
| 162 | return | ||
| 163 | } | ||
| 164 | ts[i] = param | ||
| 165 | } | ||
| 166 | return | ||
| 167 | } | ||
| 168 | |||
| 169 | func magic(t reflect.Type, s string) (i interface{}, err error) { | ||
| 170 | switch t.Kind() { | ||
| 171 | case reflect.Int: | ||
| 172 | i, err = strconv.Atoi(s) | ||
| 173 | case reflect.String: | ||
| 174 | i = s | ||
| 175 | case reflect.Ptr: | ||
| 176 | if t.Elem().String() != "regexp.Regexp" { | ||
| 177 | err = fmt.Errorf("%s does not support", t.Elem().String()) | ||
| 178 | return | ||
| 179 | } | ||
| 180 | i, err = regexp.Compile(s) | ||
| 129 | } | 181 | } |
| 130 | return ts | 182 | return |
| 131 | } | 183 | } | ... | ... |
| ... | @@ -56,3 +56,19 @@ func TestGetValidFuncs(t *testing.T) { | ... | @@ -56,3 +56,19 @@ func TestGetValidFuncs(t *testing.T) { |
| 56 | t.Error("Range funcs should be got") | 56 | t.Error("Range funcs should be got") |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | |||
| 60 | func TestCall(t *testing.T) { | ||
| 61 | u := user{Name: "test", Age: 180} | ||
| 62 | tf := reflect.TypeOf(u) | ||
| 63 | var vfs []ValidFunc | ||
| 64 | var err error | ||
| 65 | f, _ := tf.FieldByName("Age") | ||
| 66 | if vfs, err = getValidFuncs(f); err != nil { | ||
| 67 | t.Fatal(err) | ||
| 68 | } | ||
| 69 | valid := &Validation{} | ||
| 70 | funcs.Call(vfs[1].Name, valid, u.Age, vfs[1].Params[0], vfs[1].Params[1], vfs[1].Name) | ||
| 71 | if len(valid.Errors) != 1 { | ||
| 72 | t.Error("age out of range should be has an error") | ||
| 73 | } | ||
| 74 | } | ... | ... |
| ... | @@ -2,6 +2,7 @@ package validation | ... | @@ -2,6 +2,7 @@ package validation |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "reflect" | ||
| 5 | "regexp" | 6 | "regexp" |
| 6 | ) | 7 | ) |
| 7 | 8 | ||
| ... | @@ -175,3 +176,29 @@ func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResu | ... | @@ -175,3 +176,29 @@ func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResu |
| 175 | } | 176 | } |
| 176 | return result | 177 | return result |
| 177 | } | 178 | } |
| 179 | |||
| 180 | // the obj parameter must be a struct or a struct pointer | ||
| 181 | func (v *Validation) Valid(obj interface{}) (b bool, err error) { | ||
| 182 | t := reflect.TypeOf(obj) | ||
| 183 | switch { | ||
| 184 | case isStruct(t): | ||
| 185 | case isStructPtr(t): | ||
| 186 | t = t.Elem() | ||
| 187 | default: | ||
| 188 | err = fmt.Errorf("%v must be a struct or a struct pointer", obj) | ||
| 189 | return | ||
| 190 | } | ||
| 191 | // tv := reflect.TypeOf(v) | ||
| 192 | // for i := 0; i < t.NumField(); i++ { | ||
| 193 | // f := t.Field(i) | ||
| 194 | // var vfs []ValidFunc | ||
| 195 | // if vfs, err = getValidFuncs(f); err != nil { | ||
| 196 | // return | ||
| 197 | // } | ||
| 198 | // for _, vf := range vfs { | ||
| 199 | // m, _ := tv.MethodByName(vf.Name) | ||
| 200 | // m.Func | ||
| 201 | // } | ||
| 202 | // } | ||
| 203 | return | ||
| 204 | } | ... | ... |
| ... | @@ -57,16 +57,16 @@ func TestMax(t *testing.T) { | ... | @@ -57,16 +57,16 @@ func TestMax(t *testing.T) { |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | func TestRange(t *testing.T) { | 60 | // func TestRange(t *testing.T) { |
| 61 | valid := Validation{} | 61 | // valid := Validation{} |
| 62 | 62 | ||
| 63 | if valid.Range(-1, 0, 1, "range0_1").Ok { | 63 | // if valid.Range(-1, 0, 1, "range0_1").Ok { |
| 64 | t.Error("-1 is bettween 0 and 1 should be false") | 64 | // t.Error("-1 is bettween 0 and 1 should be false") |
| 65 | } | 65 | // } |
| 66 | if !valid.Range(1, 0, 1, "range0_1").Ok { | 66 | // if !valid.Range(1, 0, 1, "range0_1").Ok { |
| 67 | t.Error("1 is bettween 0 and 1 should be true") | 67 | // t.Error("1 is bettween 0 and 1 should be true") |
| 68 | } | 68 | // } |
| 69 | } | 69 | // } |
| 70 | 70 | ||
| 71 | func TestMinSize(t *testing.T) { | 71 | func TestMinSize(t *testing.T) { |
| 72 | valid := Validation{} | 72 | valid := Validation{} | ... | ... |
| ... | @@ -63,7 +63,7 @@ func (m Min) IsSatisfied(obj interface{}) bool { | ... | @@ -63,7 +63,7 @@ func (m Min) IsSatisfied(obj interface{}) bool { |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | func (m Min) DefaultMessage() string { | 65 | func (m Min) DefaultMessage() string { |
| 66 | return fmt.Sprintln("Minimum is", m.Min) | 66 | return fmt.Sprint("Minimum is ", m.Min) |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | func (m Min) GetKey() string { | 69 | func (m Min) GetKey() string { |
| ... | @@ -84,7 +84,7 @@ func (m Max) IsSatisfied(obj interface{}) bool { | ... | @@ -84,7 +84,7 @@ func (m Max) IsSatisfied(obj interface{}) bool { |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | func (m Max) DefaultMessage() string { | 86 | func (m Max) DefaultMessage() string { |
| 87 | return fmt.Sprintln("Maximum is", m.Max) | 87 | return fmt.Sprint("Maximum is ", m.Max) |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | func (m Max) GetKey() string { | 90 | func (m Max) GetKey() string { |
| ... | @@ -103,7 +103,7 @@ func (r Range) IsSatisfied(obj interface{}) bool { | ... | @@ -103,7 +103,7 @@ func (r Range) IsSatisfied(obj interface{}) bool { |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | func (r Range) DefaultMessage() string { | 105 | func (r Range) DefaultMessage() string { |
| 106 | return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max) | 106 | return fmt.Sprint("Range is ", r.Min.Min, " to ", r.Max.Max) |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | func (r Range) GetKey() string { | 109 | func (r Range) GetKey() string { |
| ... | @@ -128,7 +128,7 @@ func (m MinSize) IsSatisfied(obj interface{}) bool { | ... | @@ -128,7 +128,7 @@ func (m MinSize) IsSatisfied(obj interface{}) bool { |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | func (m MinSize) DefaultMessage() string { | 130 | func (m MinSize) DefaultMessage() string { |
| 131 | return fmt.Sprintln("Minimum size is", m.Min) | 131 | return fmt.Sprint("Minimum size is ", m.Min) |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | func (m MinSize) GetKey() string { | 134 | func (m MinSize) GetKey() string { |
| ... | @@ -153,7 +153,7 @@ func (m MaxSize) IsSatisfied(obj interface{}) bool { | ... | @@ -153,7 +153,7 @@ func (m MaxSize) IsSatisfied(obj interface{}) bool { |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | func (m MaxSize) DefaultMessage() string { | 155 | func (m MaxSize) DefaultMessage() string { |
| 156 | return fmt.Sprintln("Maximum size is", m.Max) | 156 | return fmt.Sprint("Maximum size is ", m.Max) |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | func (m MaxSize) GetKey() string { | 159 | func (m MaxSize) GetKey() string { |
| ... | @@ -178,7 +178,7 @@ func (l Length) IsSatisfied(obj interface{}) bool { | ... | @@ -178,7 +178,7 @@ func (l Length) IsSatisfied(obj interface{}) bool { |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | func (l Length) DefaultMessage() string { | 180 | func (l Length) DefaultMessage() string { |
| 181 | return fmt.Sprintln("Required length is", l.N) | 181 | return fmt.Sprint("Required length is ", l.N) |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | func (l Length) GetKey() string { | 184 | func (l Length) GetKey() string { |
| ... | @@ -202,7 +202,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool { | ... | @@ -202,7 +202,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool { |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | func (a Alpha) DefaultMessage() string { | 204 | func (a Alpha) DefaultMessage() string { |
| 205 | return fmt.Sprintln("Must be valid alpha characters") | 205 | return fmt.Sprint("Must be valid alpha characters") |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | func (a Alpha) GetKey() string { | 208 | func (a Alpha) GetKey() string { |
| ... | @@ -226,7 +226,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool { | ... | @@ -226,7 +226,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool { |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | func (n Numeric) DefaultMessage() string { | 228 | func (n Numeric) DefaultMessage() string { |
| 229 | return fmt.Sprintln("Must be valid numeric characters") | 229 | return fmt.Sprint("Must be valid numeric characters") |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | func (n Numeric) GetKey() string { | 232 | func (n Numeric) GetKey() string { |
| ... | @@ -250,7 +250,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { | ... | @@ -250,7 +250,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | func (a AlphaNumeric) DefaultMessage() string { | 252 | func (a AlphaNumeric) DefaultMessage() string { |
| 253 | return fmt.Sprintln("Must be valid alpha or numeric characters") | 253 | return fmt.Sprint("Must be valid alpha or numeric characters") |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | func (a AlphaNumeric) GetKey() string { | 256 | func (a AlphaNumeric) GetKey() string { |
| ... | @@ -269,7 +269,7 @@ func (m Match) IsSatisfied(obj interface{}) bool { | ... | @@ -269,7 +269,7 @@ func (m Match) IsSatisfied(obj interface{}) bool { |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | func (m Match) DefaultMessage() string { | 271 | func (m Match) DefaultMessage() string { |
| 272 | return fmt.Sprintln("Must match", m.Regexp) | 272 | return fmt.Sprint("Must match ", m.Regexp) |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | func (m Match) GetKey() string { | 275 | func (m Match) GetKey() string { |
| ... | @@ -287,7 +287,7 @@ func (n NoMatch) IsSatisfied(obj interface{}) bool { | ... | @@ -287,7 +287,7 @@ func (n NoMatch) IsSatisfied(obj interface{}) bool { |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | func (n NoMatch) DefaultMessage() string { | 289 | func (n NoMatch) DefaultMessage() string { |
| 290 | return fmt.Sprintln("Must not match", n.Regexp) | 290 | return fmt.Sprint("Must not match ", n.Regexp) |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | func (n NoMatch) GetKey() string { | 293 | func (n NoMatch) GetKey() string { |
| ... | @@ -302,7 +302,7 @@ type AlphaDash struct { | ... | @@ -302,7 +302,7 @@ type AlphaDash struct { |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | func (a AlphaDash) DefaultMessage() string { | 304 | func (a AlphaDash) DefaultMessage() string { |
| 305 | return fmt.Sprintln("Must be valid alpha or numeric or dash(-_) characters") | 305 | return fmt.Sprint("Must be valid alpha or numeric or dash(-_) characters") |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | func (a AlphaDash) GetKey() string { | 308 | func (a AlphaDash) GetKey() string { |
| ... | @@ -317,7 +317,7 @@ type Email struct { | ... | @@ -317,7 +317,7 @@ type Email struct { |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | func (e Email) DefaultMessage() string { | 319 | func (e Email) DefaultMessage() string { |
| 320 | return fmt.Sprintln("Must be a valid email address") | 320 | return fmt.Sprint("Must be a valid email address") |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | func (e Email) GetKey() string { | 323 | func (e Email) GetKey() string { |
| ... | @@ -332,7 +332,7 @@ type IP struct { | ... | @@ -332,7 +332,7 @@ type IP struct { |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | func (i IP) DefaultMessage() string { | 334 | func (i IP) DefaultMessage() string { |
| 335 | return fmt.Sprintln("Must be a valid ip address") | 335 | return fmt.Sprint("Must be a valid ip address") |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | func (i IP) GetKey() string { | 338 | func (i IP) GetKey() string { |
| ... | @@ -347,7 +347,7 @@ type Base64 struct { | ... | @@ -347,7 +347,7 @@ type Base64 struct { |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | func (b Base64) DefaultMessage() string { | 349 | func (b Base64) DefaultMessage() string { |
| 350 | return fmt.Sprintln("Must be valid base64 characters") | 350 | return fmt.Sprint("Must be valid base64 characters") |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | func (b Base64) GetKey() string { | 353 | func (b Base64) GetKey() string { | ... | ... |
-
Please register or sign in to post a comment