org.scalactic.Normalization.scala Maven / Gradle / Ivy
/*
* 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
/**
* Defines a custom way to normalize instances of a type.
*
*
* For example, to normalize Double
s by truncating off any decimal part,
* you might write:
*
*
*
* import org.scalactic._
*
* val truncated =
* new Normalization[Double] {
* def normalized(d: Double) = d.floor
* }
*
*
*
* Given this definition you could use it with the Explicitly
DSL like this:
*
*
*
* import org.scalatest._
* import Matchers._
* import TypeCheckedTripleEquals._
*
* (2.1 should === (2.0)) (after being truncated)
*
*
*
* Note that to use a Normalization
with the Explicitly
DSL, you'll need to use
* TypeCheckedTripleEquals
.
* If you're just using plain-old
* TripleEquals
, you'll need a Uniformity
, a Normalization
subclass.
*
*
*
* If you make the truncated
val
implicit and import or mix in the members of NormMethods
,
* you can access the behavior by invoking .norm
on Double
s.
*
*
*
* implicit val doubleNormalization = truncated
* import NormMethods._
*
* val d = 2.1
* d.norm // returns 2.0
*
*
* @tparam A the type whose normalization is being defined
*/
trait Normalization[A] { thisNormalization =>
/**
* Returns a normalized form of the passed object.
*
*
* If the passed object is already in normal form, this method may return the same instance passed.
*
*
* @tparam A the type of the object to normalize
* @param a the object to normalize
* @return the normalized form of the passed object
*/
def normalized(a: A): A
/**
* Returns a new Normalization
that composes this and the passed Normalization
.
*
*
* The normalized
method of the Normalization
returned by this method returns a normalized form of the passed
* object obtained by forwarding the passed value first to this Normalization
's normalized
method,
* then passing that result to the other Normalization
's normalized
method.
* Essentially, the body of the composed normalized
method is:
*
*
*
* normalizationPassedToAnd.normalized(normalizationOnWhichAndWasInvoked.normalized(a))
*
*
* @param other a Normalization
to 'and' with this one
* @return a Normalization
representing the composition of this and the passed Normalization
*/
infix
final def and(other: Normalization[A]): Normalization[A] =
new Normalization[A] {
def normalized(a: A): A = other.normalized(thisNormalization.normalized(a))
}
/**
* Converts this Normalization
to a NormalizingEquivalence[A]
whose normalized
* method delegates to this Normalization[A]
and whose afterNormalizationEquivalence
field returns the
* implicitly passed Equivalence[A]
.
*
* @param equivalence the Equivalence
that the returned NormalizingEquivalence
* will delegate to determine equality after normalizing both left and right (if appropriate) sides.
*/
final def toEquivalence(implicit equivalence: Equivalence[A]): NormalizingEquivalence[A] =
new NormalizingEquivalence[A] {
override val afterNormalizationEquivalence = equivalence
def normalized(a: A): A = thisNormalization.normalized(a)
}
}