vala

package module
v0.0.0-...-42e1d8b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 10, 2017 License: MIT Imports: 3 Imported by: 55

README

vala GoDoc

A simple, extensible, library to make argument validation in Go palatable.

Instead of this:

func BoringValidation(a, b, c, d, e, f, g MyType) {
  if (a == nil)
    panic("a is nil")
  if (b == nil)
    panic("b is nil")
  if (c == nil)
    panic("c is nil")
  if (d == nil)
    panic("d is nil")
  if (e == nil)
    panic("e is nil")
  if (f == nil)
    panic("f is nil")
  if (g == nil)
    panic("g is nil")
}

Do this:

func ClearValidation(a, b, c, d, e, f, g MyType) {
  BeginValidation().Validate(
    IsNotNil(a, "a"),
    IsNotNil(b, "b"),
    IsNotNil(c, "c"),
    IsNotNil(d, "d"),
    IsNotNil(e, "e"),
    IsNotNil(f, "f"),
    IsNotNil(g, "g"),
  ).CheckAndPanic() // All values will get checked before an error is thrown!
}

Instead of this:

func BoringValidation(a, b, c, d, e, f, g MyType) error {
  if (a == nil)
    return fmt.Errorf("a is nil")
  if (b == nil)
    return fmt.Errorf("b is nil")
  if (c == nil)
    return fmt.Errorf("c is nil")
  if (d == nil)
    return fmt.Errorf("d is nil")
  if (e == nil)
    return fmt.Errorf("e is nil")
  if (f == nil)
    return fmt.Errorf("f is nil")
  if (g == nil)
    return fmt.Errorf("g is nil")
}

Do this:

func ClearValidation(a, b, c, d, e, f, g MyType) (err error) {
  defer func() { recover() }
  BeginValidation().Validate(
    IsNotNil(a, "a"),
    IsNotNil(b, "b"),
    IsNotNil(c, "c"),
    IsNotNil(d, "d"),
    IsNotNil(e, "e"),
    IsNotNil(f, "f"),
    IsNotNil(g, "g"),
  ).CheckSetErrorAndPanic(&err) // Return error will get set, and the function will return.

  // ...

  VeryExpensiveFunction(c, d)
}

Tier your validation:

func ClearValidation(a, b, c MyType) (err error) {
  err = BeginValidation().Validate(
    IsNotNil(a, "a"),
    IsNotNil(b, "b"),
    IsNotNil(c, "c"),
  ).CheckAndPanic().Validate( // Panic will occur here if a, b, or c are nil.
    HasLen(a.Items, 50, "a.Items"),
    GreaterThan(b.UserCount, 0, "b.UserCount"),
    Equals(c.Name, "Vala", "c.name"),
    Not(Equals(c.FriendlyName, "Foo", "c.FriendlyName")),
  ).Check()

  if err != nil {
  	return err
  }

  // ...

  VeryExpensiveFunction(c, d)
}

Extend with your own validators for readability. Note that an error should always be returned so that the Not function can return a message if it passes. Unlike idiomatic Go, use the boolean to check for success.

func ReportFitsRepository(report *Report, repository *Repository) Checker {
	return func() (passes bool, err error) {

		err = fmt.Errof("A %s report does not belong in a %s repository.", report.Type, repository.Type)
		passes = (repository.Type == report.Type)
		return passes, err
	}
}

func AuthorCanUpload(authorName string, repository *Repository) Checker {
	return func() (passes bool, err error) {
        err = fmt.Errof("%s does not have access to this repository.", authorName)
		passes = !repository.AuthorCanUpload(authorName)
		return passes, err
	}
}

func AuthorIsCollaborator(authorName string, report *Report) Checker {
	return func() (passes bool, err error) {

        err = fmt.Errorf("The given author was not one of the collaborators for this report.")
		for _, collaboratorName := range report.Collaborators() {
			if collaboratorName == authorName {
				passes = true
				break
			}
		}

        return passes, err
	}
}

func HandleReport(authorName string, report *Report, repository *Repository) {

	BeginValidation().Validate(
    	AuthorIsCollaborator(authorName, report),
		AuthorCanUpload(authorName, repository),
		ReportFitsRepository(report, repository),
	).CheckAndPanic()
}

Documentation

Overview

Package vala is a simple, extensible, library to make argument validation in Go palatable.

This package uses the fluent programming style to provide simultaneously more robust and more terse parameter validation.

BeginValidation().Validate(
	IsNotNil(a, "a"),
	IsNotNil(b, "b"),
	IsNotNil(c, "c"),
).CheckAndPanic().Validate( // Panic will occur here if a, b, or c are nil.
	HasLen(a.Items, 50, "a.Items"),
	GreaterThan(b.UserCount, 0, "b.UserCount"),
	Equals(c.Name, "Vala", "c.name"),
	Not(Equals(c.FriendlyName, "Foo", "c.FriendlyName")),
).Check()

Notice how checks can be tiered.

Vala is also extensible. As long as a function conforms to the Checker specification, you can pass it into the Validate method:

func ReportFitsRepository(report *Report, repository *Repository) Checker {
	return func() (passes bool, err error) {

		err = fmt.Errorf("A %s report does not belong in a %s repository.", report.Type, repository.Type)
		passes = (repository.Type == report.Type)
		return passes, err
	}
}

func AuthorCanUpload(authorName string, repository *Repository) Checker {
	return func() (passes bool, err error) {
		err = fmt.Errorf("%s does not have access to this repository.", authorName)
		passes = !repository.AuthorCanUpload(authorName)
		return passes, err
	}
}

func AuthorIsCollaborator(authorName string, report *Report) Checker {
	return func() (passes bool, err error) {

		err = fmt.Errorf("The given author was not one of the collaborators for this report.")
		for _, collaboratorName := range report.Collaborators() {
			if collaboratorName == authorName {
				passes = true
				break
			}
		}

		return passes, err
	}
}

func HandleReport(authorName string, report *Report, repository *Repository) {

	BeginValidation().Validate(
		AuthorIsCollaborator(authorName, report),
		AuthorCanUpload(authorName, repository),
		ReportFitsRepository(report, repository),
	).CheckAndPanic()
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Checker

type Checker func() (checkerIsTrue bool, errorMessage string)

Checker defines the type of function which can represent a Vala checker. If the Checker fails, returns false with a corresponding error message. If the Checker succeeds, returns true, but _also_ returns an error message. This helps to support the Not function.

func Equals

func Equals(param, value interface{}, paramName string) Checker

Equals performs a basic == on the given parameters and fails if they are not equal.

func GreaterThan

func GreaterThan(param int, comparativeVal int, paramName string) Checker

GreaterThan checks to ensure the given argument is greater than the given value.

func HasLen

func HasLen(param interface{}, desiredLength int, paramName string) Checker

HasLen checks to ensure the given argument is the desired length.

func IsNotNil

func IsNotNil(obtained interface{}, paramName string) Checker

IsNotNil checks to see if the value passed in is nil. This Checker attempts to check the most performant things first, and then degrade into the less-performant, but accurate checks for nil.

func Not

func Not(checker Checker) Checker

Not returns the inverse of any Checker passed in.

func StringNotEmpty

func StringNotEmpty(obtained, paramName string) Checker

StringNotEmpty checks to ensure the given string is not empty.

type Validation

type Validation struct {
	Errors []string
}

Validation contains all the errors from performing Checkers, and is the fluent type off which all Validation methods hang.

func BeginValidation

func BeginValidation() *Validation

BeginValidation begins a validation check.

func (*Validation) Check

func (val *Validation) Check() error

Check aggregates all checker errors into a single error and returns this error.

func (*Validation) CheckAndPanic

func (val *Validation) CheckAndPanic() *Validation

CheckAndPanic aggregates all checker errors into a single error and panics with this error.

func (*Validation) CheckSetErrorAndPanic

func (val *Validation) CheckSetErrorAndPanic(retError *error) *Validation

CheckSetErrorAndPanic aggregates any Errors produced by the Checkers into a single error, and sets the address of retError to this, and panics. The canonical use-case of this is to pass in the address of an error you would like to return, and then to catch the panic and do nothing.

func (*Validation) Validate

func (val *Validation) Validate(checkers ...Checker) *Validation

Validate runs all of the checkers passed in and collects errors into an internal collection. To take action on these errors, call one of the Check* methods.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL