diff --git a/README.md b/README.md index 6105deb..072bcad 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ This package currently provides the following checkers: - [max-length](doc/checkers/maxlength.md) checks if the length of the given value is less than the given maximum length. - [min](doc/checkers/min.md) checks if the given value is greather than the given minimum. - [min-length](doc/checkers/minlength.md) checks if the length of the given value is greather than the given minimum length. +- [regexp](doc/checkers/regexp.md) checks if the given string matches the regexp pattern. - [required](doc/checkers/required.md) checks if the required value is provided. - [same](doc/checkers/same.md) checks if the given value is equal to the value of the field with the given name. diff --git a/checker.go b/checker.go index 1ee173e..3b731ef 100644 --- a/checker.go +++ b/checker.go @@ -45,6 +45,7 @@ var makers = map[string]MakeFunc{ CheckerMaxLength: makeMaxLength, CheckerMin: makeMin, CheckerMinLength: makeMinLength, + CheckerRegexp: makeRegexp, CheckerRequired: makeRequired, CheckerSame: makeSame, NormalizerLower: makeLower, diff --git a/doc/checkers/regexp.md b/doc/checkers/regexp.md new file mode 100644 index 0000000..cf5d699 --- /dev/null +++ b/doc/checkers/regexp.md @@ -0,0 +1,48 @@ +# Regexp Checker + +The ```regexp``` checker checks if the given string matches the given regexp. If the given string does not match, the checker will return the ```NOT_MATCH``` result. Here is an example: + +```golang +type User struct { + Username string `checkers:"regexp:^[A-Za-z]+$"` +} + +user := &User{ + Username: "abcd", +} + +_, valid := Check(user) +if !valid { + // Send the mistakes back to the user +} +``` + +The ```regexp``` checker can be used to build other checkers for other regexp patterns. In order to do that, you can use the ```MakeRegexpChecker``` function. The function takes an expression and a result to return when the the given string is not a match. Here is an example: + +```golang +checkHex := MakeRegexpChecker("^[A-Fa-f0-9]+$", "NOT_HEX") + +result := checkHex(reflect.ValueOf("f0f0f0"), reflect.ValueOf(nil)) +if result != ResultValid { + // Send the mistakes back to the user +} +``` + +To register the new regexp checker to validate user input in struct, you ```MakeRegexpChecker``` function can be used. Here is an example: + +```golang +Register("hex", MakeRegexpMaker("^[A-Fa-f0-9]+$", "NOT_HEX")) + +type Theme struct { + Color string `checkers:hex` +} + +theme := &Theme{ + Color: "f0f0f0", +} + +_, valid := Check(theme) +if !valid { + // Send the mistakes back to the user +} +``` diff --git a/email.go b/email.go index 8797661..021e0e7 100644 --- a/email.go +++ b/email.go @@ -9,7 +9,7 @@ import ( // CheckerEmail is the name of the checker. const CheckerEmail = "email" -// ResultNotFqdn indicates that the given string is not a valid email. +// ResultNotEmail indicates that the given string is not a valid email. const ResultNotEmail = "NOT_EMAIL" // ipV6Prefix is the IPv6 prefix for the domain. diff --git a/regexp.go b/regexp.go new file mode 100644 index 0000000..5142b53 --- /dev/null +++ b/regexp.go @@ -0,0 +1,46 @@ +package checker + +import ( + "reflect" + "regexp" +) + +// CheckerRegexp is the name of the checker. +const CheckerRegexp = "regexp" + +// ResultNotMatch indicates that the given string does not match the regexp pattern. +const ResultNotMatch = "NOT_MATCH" + +// MakeRegexpMaker makes a regexp checker maker for the given regexp expression with the given invalid result. +func MakeRegexpMaker(expression string, invalidResult Result) MakeFunc { + return func(_ string) CheckFunc { + return MakeRegexpChecker(expression, invalidResult) + } +} + +// MakeRegexpChecker makes a regexp checker for the given regexp expression with the given invalid result. +func MakeRegexpChecker(expression string, invalidResult Result) CheckFunc { + pattern := regexp.MustCompile(expression) + + return func(value, parent reflect.Value) Result { + return checkRegexp(value, pattern, invalidResult) + } +} + +// makeRegexp makes a checker function for the regexp. +func makeRegexp(config string) CheckFunc { + return MakeRegexpChecker(config, ResultNotMatch) +} + +// checkRegexp checks if the given string matches the regexp pattern. +func checkRegexp(value reflect.Value, pattern *regexp.Regexp, invalidResult Result) Result { + if value.Kind() != reflect.String { + panic("string expected") + } + + if !pattern.MatchString(value.String()) { + return invalidResult + } + + return ResultValid +} diff --git a/regexp_test.go b/regexp_test.go new file mode 100644 index 0000000..8a8c768 --- /dev/null +++ b/regexp_test.go @@ -0,0 +1,74 @@ +package checker + +import ( + "reflect" + "testing" +) + +func TestCheckRegexpNonString(t *testing.T) { + defer FailIfNoPanic(t) + + type User struct { + Username int `checkers:"regexp:^[A-Za-z]$"` + } + + user := &User{} + + Check(user) +} + +func TestCheckRegexpInvalid(t *testing.T) { + type User struct { + Username string `checkers:"regexp:^[A-Za-z]+$"` + } + + user := &User{ + Username: "abcd1234", + } + + _, valid := Check(user) + if valid { + t.Fail() + } +} + +func TestCheckRegexpValid(t *testing.T) { + type User struct { + Username string `checkers:"regexp:^[A-Za-z]+$"` + } + + user := &User{ + Username: "abcd", + } + + _, valid := Check(user) + if !valid { + t.Fail() + } +} + +func TestMakeRegexpChecker(t *testing.T) { + checkHex := MakeRegexpChecker("^[A-Fa-f0-9]+$", "NOT_HEX") + + result := checkHex(reflect.ValueOf("f0f0f0"), reflect.ValueOf(nil)) + if result != ResultValid { + t.Fail() + } +} + +func TestMakeRegexpMaker(t *testing.T) { + Register("hex", MakeRegexpMaker("^[A-Fa-f0-9]+$", "NOT_HEX")) + + type Theme struct { + Color string `checkers:"hex"` + } + + theme := &Theme{ + Color: "f0f0f0", + } + + _, valid := Check(theme) + if !valid { + t.Fail() + } +}