Skip to content

Commit

Permalink
Changed Or and OrSpec such that Good and Bad just have one type param…
Browse files Browse the repository at this point in the history
…eter.

Conflicts:

	src/test/scala/org/scalactic/OrSpec.scala
  • Loading branch information
bvenners committed Feb 8, 2015
1 parent 5fce6e2 commit fcf3314
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 62 deletions.
79 changes: 41 additions & 38 deletions src/main/scala/org/scalactic/Or.scala
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,9 @@ sealed abstract class Or[+G,+B] {
* @return the result of applying the appropriate one of the two passed functions, <code>gf</code> or </code>bf</code>, to this <code>Or</code>'s value
*/
def fold[V](gf: G => V, bf: B => V): V

@deprecated("This is no longer necessary. Please just delete invocations of asOr")
def asOr: G Or B = this
}

/**
Expand Down Expand Up @@ -909,7 +912,7 @@ object Or {
*
* @param g the &ldquo;good&rdquo; value
*/
final case class Good[+G,+B](g: G) extends Or[G,B] {
final case class Good[+G](g: G) extends Or[G,Nothing] {
override val isGood: Boolean = true

/**
Expand Down Expand Up @@ -977,7 +980,7 @@ final case class Good[+G,+B](g: G) extends Or[G,B] {
* res3: org.scalactic.Or[Int,org.scalactic.ErrorMessage] = Good(9)
* </pre>
*/
def asOr: G Or B = this
override def asOr: G Or Nothing = this

/**
* Narrows the <code>Bad</code> type of this <code>Good</code> to the given type.
Expand All @@ -1002,31 +1005,31 @@ final case class Good[+G,+B](g: G) extends Or[G,B] {
* res1: org.scalactic.Good[Int,String] = Good(3)
* </pre>
*/
def orBad[C](implicit ev: B <:< C): Good[G, C] = this.asInstanceOf[Good[G, C]]
def orBad[C]: G Or C = this.asInstanceOf[Or[G, C]]
def get: G = g
def map[H](f: G => H): H Or B = Good(f(g))
def badMap[C](f: B => C): G Or C = this.asInstanceOf[G Or C]
def recover[H >: G](f: B => H): H Or B = this.asInstanceOf[H Or B]
def recoverWith[H >: G, C](f: B => H Or C): H Or C = this.asInstanceOf[H Or C]
def map[H](f: G => H): H Or Nothing = Good(f(g))
def badMap[C](f: Nothing => C): G Or C = this.asInstanceOf[G Or C]
def recover[H >: G](f: Nothing => H): H Or Nothing = this.asInstanceOf[H Or Nothing]
def recoverWith[H >: G, C](f: Nothing => H Or C): H Or C = this.asInstanceOf[H Or C]
def foreach(f: G => Unit): Unit = f(g)
def flatMap[H, C >: B](f: G => H Or C): H Or C = f(g)
def filter[C >: B](f: G => Validation[C]): G Or C =
def flatMap[H, C >: Nothing](f: G => H Or C): H Or C = f(g)
def filter[C >: Nothing](f: G => Validation[C]): G Or C =
f(g) match {
case Fail(error) => Bad(error)
case Pass => this
}
def exists(p: G => Boolean): Boolean = p(g)
def forall(p: G => Boolean): Boolean = p(g)
def getOrElse[H >: G](default: => H): G = g
def orElse[H >: G, C >: B](alternative: => H Or C): G Or B = this
def orElse[H >: G, C >: Nothing](alternative: => H Or C): G Or Nothing = this
def toOption: Some[G] = Some(g)
def toSeq: scala.collection.immutable.IndexedSeq[G] = Vector(g)
def toEither: Either[B, G] = Right(g)
def accumulating: G Or One[B] = Good(g)
def toTry(implicit ev: B <:< Throwable): Success[G] = Success(g)
def swap: B Or G = Bad(g)
def transform[H, C](gf: G => H Or C, bf: B => H Or C): H Or C = gf(g)
def fold[V](gf: G => V, bf: B => V): V = gf(g)
def toEither: Either[Nothing, G] = Right(g)
def accumulating: G Or One[Nothing] = Good(g)
def toTry(implicit ev: Nothing <:< Throwable): Success[G] = Success(g)
def swap: Nothing Or G = Bad(g)
def transform[H, C](gf: G => H Or C, bf: Nothing => H Or C): H Or C = gf(g)
def fold[V](gf: G => V, bf: Nothing => V): V = gf(g)
}

/**
Expand Down Expand Up @@ -1058,7 +1061,7 @@ object Good {
* @param b the &ldquo;bad&rdquo; value
* @return a new <code>Bad</code> instance containing the passed <code>b</code> value
*/
def orBad[B](b: B): Bad[G, B] = Bad[G, B](b)
def orBad[B](b: B): G Or B = Bad[B](b)

override def toString: String = "GoodType"
}
Expand Down Expand Up @@ -1102,7 +1105,7 @@ object Good {
*
* @param b the &ldquo;bad&rdquo; value
*/
final case class Bad[+G,+B](b: B) extends Or[G,B] {
final case class Bad[+B](b: B) extends Or[Nothing,B] {
override val isBad: Boolean = true

/**
Expand Down Expand Up @@ -1157,26 +1160,26 @@ final case class Bad[+G,+B](b: B) extends Or[G,B] {
* res5: org.scalactic.Or[Int,ErrorMessage] = Bad(No even nums)
* </pre>
*/
def asOr: G Or B = this
def get: G = throw new NoSuchElementException("Bad(" + b + ").get")
def map[H](f: G => H): H Or B = this.asInstanceOf[H Or B]
def badMap[C](f: B => C): G Or C = Bad(f(b))
def recover[H >: G](f: B => H): H Or B = Good(f(b))
def recoverWith[H >: G, C](f: B => H Or C): H Or C = f(b)
def foreach(f: G => Unit): Unit = ()
def flatMap[H, C >: B](f: G => H Or C): H Or C = this.asInstanceOf[H Or C]
def filter[C >: B](f: G => Validation[C]): G Or C = this
def exists(p: G => Boolean): Boolean = false
def forall(p: G => Boolean): Boolean = true
def getOrElse[H >: G](default: => H): H = default
def orElse[H >: G, C >: B](alternative: => H Or C): H Or C = alternative
override def asOr: Nothing Or B = this
def get: Nothing = throw new NoSuchElementException("Bad(" + b + ").get")
def map[H](f: Nothing => H): H Or B = this.asInstanceOf[H Or B]
def badMap[C](f: B => C): Nothing Or C = Bad(f(b))
def recover[H >: Nothing](f: B => H): H Or B = Good(f(b))
def recoverWith[H >: Nothing, C](f: B => H Or C): H Or C = f(b)
def foreach(f: Nothing => Unit): Unit = ()
def flatMap[H, C >: B](f: Nothing => H Or C): H Or C = this.asInstanceOf[H Or C]
def filter[C >: B](f: Nothing => Validation[C]): Nothing Or C = this
def exists(p: Nothing => Boolean): Boolean = false
def forall(p: Nothing => Boolean): Boolean = true
def getOrElse[H >: Nothing](default: => H): H = default
def orElse[H >: Nothing, C >: B](alternative: => H Or C): H Or C = alternative
def toOption: None.type = None
def toSeq: scala.collection.immutable.IndexedSeq[G] = Vector.empty
def toEither: Either[B, G] = Left(b)
def accumulating: G Or One[B] = Bad(One(b))
def toTry(implicit ev: B <:< Throwable): Failure[G] = Failure(b)
def swap: B Or G = Good(b)
def transform[H, C](gf: G => H Or C, bf: B => H Or C): H Or C = bf(b)
def fold[V](gf: G => V, bf: B => V): V = bf(b)
def toSeq: scala.collection.immutable.IndexedSeq[Nothing] = Vector.empty
def toEither: Either[B, Nothing] = Left(b)
def accumulating: Nothing Or One[B] = Bad(One(b))
def toTry(implicit ev: B <:< Throwable): Failure[Nothing] = Failure(b)
def swap: B Or Nothing = Good(b)
def transform[H, C](gf: Nothing => H Or C, bf: B => H Or C): H Or C = bf(b)
def fold[V](gf: Nothing => V, bf: B => V): V = bf(b)
}

48 changes: 24 additions & 24 deletions src/test/scala/org/scalactic/OrSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class OrSpec extends UnitSpec with Accumulation with TypeCheckedTripleEquals {
Bad("oops") shouldBe 'bad

Good(7) shouldBe an [Or[_, _]]
Good(7) shouldBe an [Good[_, _]]
Good(7) shouldBe an [Good[_]]

Bad("oops") shouldBe an [Or[_, _]]
Bad("oops") shouldBe an [Bad[_, _]]
Bad("oops") shouldBe an [Bad[_]]
}
it can "have its non-inferred type widened by an apply call with a type param" in {
/*
Expand Down Expand Up @@ -76,14 +76,14 @@ class OrSpec extends UnitSpec with Accumulation with TypeCheckedTripleEquals {
Good[Int].orBad("oops") shouldBe Bad("oops")

// You could also do it this way:
Good[Int, String](3) shouldBe Good(3)
Bad[Int, String]("oops") shouldBe Bad("oops")
Good[Int](3) shouldBe Good(3)
Bad[String]("oops") shouldBe Bad("oops")

// But that requires that you also give a type that would be inferred from the value. This
// would only be necessary if you wanted a more general type than that which
// would otherwise be inferred from the given value, such as:
Good[AnyVal, String](3) shouldBe Good(3)
Bad[Int, AnyRef]("oops") shouldBe Bad("oops")
Good[AnyVal](3) shouldBe Good(3)
Bad[AnyRef]("oops") shouldBe Bad("oops")

// In that case, though, I recommend a type ascription, because I think it is easier to read:
(Good(3): AnyVal Or String) shouldBe Good(3)
Expand Down Expand Up @@ -233,18 +233,18 @@ class OrSpec extends UnitSpec with Accumulation with TypeCheckedTripleEquals {
it can "be used with zip" in {
Good(12).orBad[Every[ErrorMessage]] zip Good("hi").orBad[Every[ErrorMessage]] should === (Good((12, "hi")).orBad[Every[ErrorMessage]])
Good[Int].orBad(One("so")) zip Good[String].orBad(One("ho")) should === (Bad(Many("so", "ho")))
(Good(12): Int Or Every[ErrorMessage]) zip Bad[String, Every[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[Int, Every[ErrorMessage]](One("so")) zip Good[String, Every[ErrorMessage]]("hi") should === (Bad(One("so")))
(Good(12): Int Or Every[ErrorMessage]) zip Bad[Every[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[Every[ErrorMessage]](One("so")) zip Good[String]("hi") should === (Bad(One("so")))

Good[Int, One[ErrorMessage]](12) zip Good[String, Every[ErrorMessage]]("hi") should === (Good[(Int, String), Every[ErrorMessage]]((12, "hi")))
Bad[Int, One[ErrorMessage]](One("so")) zip Bad[String, Every[ErrorMessage]](One("ho")) should === (Bad(Many("so", "ho")))
Good[Int, One[ErrorMessage]](12) zip Bad[String, Every[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[Int, One[ErrorMessage]](One("so")) zip Good[String, Every[ErrorMessage]]("hi") should === (Bad(One("so")))
Good[Int](12) zip Good[String]("hi") should === (Good[(Int, String)]((12, "hi")))
Bad[One[ErrorMessage]](One("so")) zip Bad[Every[ErrorMessage]](One("ho")) should === (Bad(Many("so", "ho")))
Good[Int](12) zip Bad[Every[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[One[ErrorMessage]](One("so")) zip Good[String]("hi") should === (Bad(One("so")))

Good[Int, Every[ErrorMessage]](12) zip Good[String, One[ErrorMessage]]("hi") should === (Good[(Int, String), Every[ErrorMessage]]((12, "hi")))
Bad[Int, Every[ErrorMessage]](One("so")) zip Bad[String, One[ErrorMessage]](One("ho")) should === (Bad(Many("so", "ho")))
Good[Int, Every[ErrorMessage]](12) zip Bad[String, One[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[Int, Every[ErrorMessage]](One("so")) zip Good[String, One[ErrorMessage]]("hi") should === (Bad(One("so")))
Good[Int](12) zip Good[String]("hi") should === (Good[(Int, String)]((12, "hi")))
Bad[Every[ErrorMessage]](One("so")) zip Bad[One[ErrorMessage]](One("ho")) should === (Bad(Many("so", "ho")))
Good[Int](12) zip Bad[One[ErrorMessage]](One("ho")) should === (Bad(One("ho")))
Bad[Every[ErrorMessage]](One("so")) zip Good[String]("hi") should === (Bad(One("so")))

// Works when right hand side ERR type is a supertype of left hand side ERR type, because that's what Every's ++ does.
Good[Int].orBad(One("oops")) zip Good[Int].orBad(One(-1: Any)) shouldBe Bad(Many("oops", -1))
Expand All @@ -254,32 +254,32 @@ class OrSpec extends UnitSpec with Accumulation with TypeCheckedTripleEquals {
}

it can "be used with when" in {
Good[Int, Every[ErrorMessage]](12).when(
Good[Int](12).when(
(i: Int) => if (i > 0) Pass else Fail(i + " was not greater than 0"),
(i: Int) => if (i < 100) Pass else Fail(i + " was not less than 100"),
(i: Int) => if (i % 2 == 0) Pass else Fail(i + " was not even")
) shouldBe Good(12)
Good[Int, Every[ErrorMessage]](12).when(
Good[Int](12).when(
(i: Int) => if (i > 0) Pass else Fail(i + " was not greater than 0"),
(i: Int) => if (i < 3) Pass else Fail(i + " was not less than 3"),
(i: Int) => if (i % 2 == 0) Pass else Fail(i + " was not even")
) shouldBe Bad(One("12 was not less than 3"))
Good[Int, Every[ErrorMessage]](12).when(
Good[Int](12).when(
(i: Int) => if (i > 0) Pass else Fail(i + " was not greater than 0"),
(i: Int) => if (i < 3) Pass else Fail(i + " was not less than 3"),
(i: Int) => if (i % 2 == 1) Pass else Fail(i + " was not odd")
) shouldBe Bad(Many("12 was not less than 3", "12 was not odd"))
Good[Int, Every[ErrorMessage]](12).when(
Good[Int](12).when(
(i: Int) => if (i > 99) Pass else Fail(i + " was not greater than 99"),
(i: Int) => if (i < 3) Pass else Fail(i + " was not less than 3"),
(i: Int) => if (i % 2 == 1) Pass else Fail(i + " was not odd")
) shouldBe Bad(Many("12 was not greater than 99", "12 was not less than 3", "12 was not odd"))
Bad[Int, Every[ErrorMessage]](One("original error")).when(
Good[Int].orBad[Every[ErrorMessage]](One("original error")).when(
(i: Int) => if (i > 0) Pass else Fail(i + " was not greater than 0"),
(i: Int) => if (i < 3) Pass else Fail(i + " was not less than 3"),
(i: Int) => if (i % 2 == 0) Pass else Fail(i + " was not even")
) shouldBe Bad(One("original error"))
Bad[Int, Every[ErrorMessage]](Many("original error 1", "original error 2")).when(
Good[Int].orBad[Every[ErrorMessage]](Many("original error 1", "original error 2")).when(
(i: Int) => if (i > 0) Pass else Fail(i + " was not greater than 0"),
(i: Int) => if (i < 3) Pass else Fail(i + " was not less than 3"),
(i: Int) => if (i % 2 == 0) Pass else Fail(i + " was not even")
Expand Down Expand Up @@ -485,8 +485,8 @@ class OrSpec extends UnitSpec with Accumulation with TypeCheckedTripleEquals {

// Set
Set.empty[Int Or Every[String]].combined shouldBe Good(Set.empty[Int])
Set(Good[Int, Every[String]](3), Bad[Int, Every[String]](Every("oops"))).asInstanceOf[Set[Int Or Every[String]]].combined shouldBe Bad(One("oops"))
Set(Good[Int, Every[String]](3), Bad[Int, Every[String]](Every("oops"))).combined shouldBe Bad(One("oops"))
Set(Good[Int](3), Bad[Every[String]](Every("oops"))).asInstanceOf[Set[Int Or Every[String]]].combined shouldBe Bad(One("oops"))
Set(Good[Int](3), Bad[Every[String]](Every("oops"))).combined shouldBe Bad(One("oops"))

Set(Good(3)).combined shouldBe Good(Set(3))
Set(Bad(One("oops"))).combined shouldBe Bad(One("oops"))
Expand Down

0 comments on commit fcf3314

Please sign in to comment.