All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalactic.Validation.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2001-2013 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scalactic

/**
 * Represents the result of a validation, either the object Pass if the validation 
 * succeeded, else an instance of Fail containing an error value describing the validation failure.
 *
 * 

* Validations are used to filter Ors in for expressions or filter method calls. * For example, consider these methods: *

* *
 * import org.scalactic._
 *
 * def isRound(i: Int): Validation[ErrorMessage] =
 *   if (i % 10 == 0) Pass else Fail(i + " was not a round number")
 *
 * def isDivBy3(i: Int): Validation[ErrorMessage] =
 *   if (i % 3 == 0) Pass else Fail(i + " was not divisible by 3")
 * 
* *

* Because isRound and isDivBy3 take an Int and return a Validation[ErrorMessage], you * can use them in filters in for expressions involving Ors of type Int Or ErrorMessage. * Here's an example: *

* *
 * for (i <- Good(3) if isRound(i) && isDivBy3(i)) yield i
 * // Result: Bad(3 was not a round number)
 * 
* *

* Validations can also be used to accumulate error using when, a method that's made available by trait Accumulation on * accumualting Ors (Ors whose Bad type is an Every[T]). Here are some examples: *

* *
 * import Accumulation._
 *
 * for (i <- Good(3) when (isRound, isDivBy3)) yield i
 * // Result: Bad(One(3 was not a round number))
 *
 * for (i <- Good(4) when (isRound, isDivBy3)) yield i
 * // Result: Bad(Many(4 was not a round number, 4 was not divisible by 3))
 * 
* *

* Note: You can think of Validation as an “Option with attitude,” where Pass is * a None that indicates validation success and Fail is a Some whose value describes * the validation failure. *

* * @tparam E the type of error value describing a validation failure for this Validation */ sealed trait Validation[+E] extends Product with Serializable { /** * Ands this Validation with another, passed, Validation. * *

* The result of and-ing two Validations is: *

* * * * * * *
ExpressionResult
Pass && PassPass
Pass && Fail(right)Fail(right)
Fail(left) && PassFail(left)
Fail(left) && Fail(right)Fail(left)
* *

* As you can see in the above table, no attempt is made by && to accumulate errors, which in turn means that * no constraint is placed on the E type (it need not be an Every). Instead, && short circuits * and returns the first Fail it encounters. This makes it useful in filters in for expressions involving Ors. * Here's an example: *

* *
   * import org.scalactic._
   *
   * def isRound(i: Int): Validation[ErrorMessage] =
   *   if (i % 10 != 0) Fail(i + " was not a round number") else Pass
   *
   * def isDivBy3(i: Int): Validation[ErrorMessage] =
   *   if (i % 3 != 0) Fail(i + " was not divisible by 3") else Pass
   *
   * for (i <- Good(3) if isRound(i) && isDivBy3(i)) yield i
   * // Result: Bad(3 was not a round number)
   * 
* * @param other the other validation to and with this one * @return the result of anding this Validation with the other, passed, Validation */ def &&[F >: E](other: => Validation[F]): Validation[F] } /** * Indicates a validation succeeded. */ case object Pass extends Validation[Nothing] { /** * Ands this Validation with another, passed, Validation. * *

* The result of invoking this method will be the result of executing the passed other by-name value. *

* * @param other the other validation to and with this one * @return the result of anding this Validation with the other, passed, Validation */ def &&[F](other: => Validation[F]): Validation[F] = other } /** * Indicates a validation failed, describing the failure with a contained error value. * * @param error an error value describing the validation failure * @tparam E the type of value describing a validation failure for this Fail */ case class Fail[E](error: E) extends Validation[E] { /** * Ands this Validation with another, passed, Validation. * *

* The result of invoking this method will be this same Fail object. It will not execute the passed by-name. *

* * @param other the other validation to and with this one * @return the result of anding this Validation with the other, passed, Validation */ def &&[F >: E](other: => Validation[F]): Validation[F] = this } /* OK, I can keep Validation simple like this, and it will only support &&, which will short-circuit like && does, at least in the error message. And when I do Expectation, maybe I could put it in Scalactic, and have an implicit conversion in the Expectation or Validation companion object that goes from Expectation to Validation *if* the error type is String. Though not sure that's really a good way to create error messages for non-programmers. */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy