Permalink
Browse files

Allow arbitrary validation error messages

  • Loading branch information...
1 parent 24858e8 commit 87d2edfce87dbe4a867cd1327cc31579308bd93f @thomaslee committed Mar 27, 2012
Showing with 127 additions and 30 deletions.
  1. +112 −30 gtfo.go
  2. +15 −0 gtfo_test.go
View
142 gtfo.go
@@ -10,8 +10,13 @@ type ValidationError struct {
message string
}
+func (err *ValidationError) Message() string {
+ return err.message
+}
+
type Validator interface {
Validate(form *Form, field *Field, value string) []ValidationError
+ SetMessage(message string)
}
type Form struct {
@@ -67,13 +72,29 @@ func (field *Field) Validate(value string) []ValidationError {
return errors
}
-type requiredValidator struct{}
+type baseValidator struct {
+ message string
+}
+
+func (v *baseValidator) SetMessage(message string) {
+ v.message = message
+}
+
+type requiredValidator struct {
+ baseValidator
+}
var required requiredValidator
func (req *requiredValidator) Validate(form *Form, field *Field, value string) []ValidationError {
if len(value) == 0 {
- return []ValidationError{ValidationError{message: fmt.Sprintf("%v is required", field.Name)}}
+ var message string
+ if req.message == "" {
+ message = fmt.Sprintf("%v is required", field.Name)
+ } else {
+ message = req.message
+ }
+ return []ValidationError{ValidationError{message: message}}
}
return []ValidationError{}
}
@@ -84,6 +105,7 @@ const (
)
type lengthValidator struct {
+ baseValidator
flags uint
minimum int
maximum int
@@ -93,35 +115,52 @@ func (l *lengthValidator) Validate(form *Form, field *Field, value string) []Val
errors := []ValidationError{}
if (l.flags & useMinimum) == useMinimum {
if len(value) < l.minimum {
- messageFormat := "%v must be at least %v characters long"
- message := fmt.Sprintf(messageFormat, field.Name, l.minimum)
+ var message string
+ if l.message == "" {
+ messageFormat := "%v must be at least %v characters long"
+ message = fmt.Sprintf(messageFormat, field.Name, l.minimum)
+ } else {
+ message = l.message
+ }
errors = append(errors, ValidationError{message: message})
}
} else if (l.flags & useMaximum) == useMaximum {
if len(value) > l.maximum {
- messageFormat := "%v must be no more than %v characters long"
- message := fmt.Sprintf(messageFormat, field.Name, l.maximum)
+ var message string
+ if l.message == "" {
+ messageFormat := "%v must be no more than %v characters long"
+ message = fmt.Sprintf(messageFormat, field.Name, l.maximum)
+ } else {
+ message = l.message
+ }
errors = append(errors, ValidationError{message: message})
}
}
return errors
}
type regexValidator struct {
+ baseValidator
pattern *regexp.Regexp
}
func (v *regexValidator) Validate(form *Form, field *Field, value string) []ValidationError {
errors := []ValidationError{}
if !v.pattern.MatchString(value) {
- messageFormat := "%v is not in the correct format"
- message := fmt.Sprintf(messageFormat, field.Name)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v is not in the correct format"
+ message = fmt.Sprintf(messageFormat, field.Name)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
return errors
}
type rangeIntValidator struct {
+ baseValidator
flags uint
minimum int
maximum int
@@ -135,36 +174,61 @@ func (v *rangeIntValidator) Validate(form *Form, field *Field, value string) []V
if (v.flags & useMinimum) == useMinimum {
if v.inclusive {
if inputValue <= v.minimum {
- messageFormat := "%v must be greater than %v"
- message := fmt.Sprintf(messageFormat, field.Name, v.minimum)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v must be greater than %v"
+ message = fmt.Sprintf(messageFormat, field.Name, v.minimum)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
} else {
if inputValue < v.minimum {
- messageFormat := "%v must be greater than or equal to %v"
- message := fmt.Sprintf(messageFormat, field.Name, v.minimum)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v must be greater than or equal to %v"
+ message = fmt.Sprintf(messageFormat, field.Name, v.minimum)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
}
}
if (v.flags & useMaximum) == useMaximum {
if v.inclusive {
if inputValue >= v.maximum {
- messageFormat := "%v must be less than %v"
- message := fmt.Sprintf(messageFormat, field.Name, v.maximum)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v must be less than %v"
+ message = fmt.Sprintf(messageFormat, field.Name, v.maximum)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
} else {
if inputValue > v.maximum {
- messageFormat := "%v must be less than or equal to %v"
- message := fmt.Sprintf(messageFormat, field.Name, v.maximum)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v must be less than or equal to %v"
+ message = fmt.Sprintf(messageFormat, field.Name, v.maximum)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
}
}
} else {
- messageFormat := "%v must have an integer value"
- message := fmt.Sprintf(messageFormat, field.Name)
+ var message string
+ if v.message == "" {
+ messageFormat := "%v must have an integer value"
+ message = fmt.Sprintf(messageFormat, field.Name)
+ } else {
+ message = v.message
+ }
errors = append(errors, ValidationError{message: message})
}
return errors
@@ -174,27 +238,45 @@ func Required() Validator {
return &required
}
-func MinLength(value int) Validator {
- return &lengthValidator{flags: useMinimum, minimum: value}
+func MinLength(value int, optional ...interface{}) Validator {
+ result := &lengthValidator{flags: useMinimum, minimum: value}
+ return applyValidatorArgs(result, optional)
}
-func MaxLength(value int) Validator {
- return &lengthValidator{flags: useMaximum, maximum: value}
+func MaxLength(value int, optional ...interface{}) Validator {
+ result := &lengthValidator{flags: useMaximum, maximum: value}
+ return applyValidatorArgs(result, optional)
}
-func Matches(regex string) Validator {
- return &regexValidator{pattern: regexp.MustCompile(regex)}
+func Matches(regex string, optional ...interface{}) Validator {
+ result := &regexValidator{pattern: regexp.MustCompile(regex)}
+ return applyValidatorArgs(result, optional)
}
-func GreaterInt(minimum int) Validator {
- return &rangeIntValidator{flags: useMinimum, minimum: minimum, inclusive: true}
+func GreaterInt(minimum int, optional ...interface{}) Validator {
+ result := &rangeIntValidator{flags: useMinimum, minimum: minimum, inclusive: true}
+ return applyValidatorArgs(result, optional)
}
-func LessInt(maximum int) Validator {
- return &rangeIntValidator{flags: useMaximum, maximum: maximum, inclusive: true}
+func LessInt(maximum int, optional ...interface{}) Validator {
+ result := &rangeIntValidator{flags: useMaximum, maximum: maximum, inclusive: true}
+ return applyValidatorArgs(result, optional)
}
-func BetweenInt(minimum, maximum int) Validator {
- return &rangeIntValidator{flags: useMinimum | useMaximum, minimum: minimum, maximum: maximum, inclusive: false}
+func BetweenInt(minimum, maximum int, optional ...interface{}) Validator {
+ result := &rangeIntValidator{flags: useMinimum | useMaximum, minimum: minimum, maximum: maximum, inclusive: false}
+ return applyValidatorArgs(result, optional)
+}
+
+func applyValidatorArgs(validator Validator, optional []interface{}) Validator {
+ if len(optional) == 1 {
+ switch message := optional[0].(type) {
+ case string:
+ validator.SetMessage(message)
+ default:
+ panic("Unknown or unexpected argument type")
+ }
+ }
+ return validator
}
View
15 gtfo_test.go
@@ -68,6 +68,21 @@ func TestRangeIntValidator(t *testing.T) {
checkFormWithInputs(t, form, pass, fail)
}
+func TestRangeIntValidatorWithMessage(t *testing.T) {
+ const message string = "You're not old enough!"
+
+ form := &Form{}
+ form.Field("age", GreaterInt(20, message))
+ input := map[string]string{"age": "20"}
+ errors := form.Validate(input)
+ if len(errors) == 0 {
+ t.Errorf("Expected a validation error")
+ }
+ if errors[0].Message() != message {
+ t.Errorf("Expected '%v', but got '%v'", message, errors[0].Message())
+ }
+}
+
func checkFormWithInputs(t *testing.T, form *Form, pass, fail []map[string]string) {
for _, params := range pass {
errors := form.Validate(params)

0 comments on commit 87d2edf

Please sign in to comment.