From 826b2119627e15813f991fcd45ca4c71dbc55c44 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Feb 2017 23:42:52 -0500 Subject: [PATCH 01/17] Added Ior syntax --- core/src/main/scala/cats/data/Ior.scala | 8 ++ core/src/main/scala/cats/data/package.scala | 1 + core/src/main/scala/cats/syntax/ior.scala | 115 ++++++++++++++++++ core/src/main/scala/cats/syntax/package.scala | 1 + 4 files changed, 125 insertions(+) create mode 100644 core/src/main/scala/cats/syntax/ior.scala diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 8b79aa013a..24d65a5317 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -1,7 +1,9 @@ package cats package data +import cats.data.Validated.{Invalid, Valid} import cats.functor.Bifunctor + import scala.annotation.tailrec /** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`. @@ -47,6 +49,9 @@ sealed abstract class Ior[+A, +B] extends Product with Serializable { final def unwrap: Either[Either[A, B], (A, B)] = fold(a => Left(Left(a)), b => Left(Right(b)), (a, b) => Right((a, b))) final def toEither: Either[A, B] = fold(Left(_), Right(_), (_, b) => Right(b)) + final def toValidated: Validated[A, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b)) + final def toValidatedNel: ValidatedNel[A, B] = fold(Validated.invalidNel, Valid(_), (_, b) => Valid(b)) + final def toValidatedNel[C](implicit ev: A <:< NonEmptyList[C]): ValidatedNel[C, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b)) final def toOption: Option[B] = right final def toList: List[B] = right.toList @@ -198,6 +203,9 @@ private[data] sealed trait IorFunctions { def left[A, B](a: A): A Ior B = Ior.Left(a) def right[A, B](b: B): A Ior B = Ior.Right(b) def both[A, B](a: A, b: B): A Ior B = Ior.Both(a, b) + def rightNel[A, B](b: B): IorNel[A, B] = right(NonEmptyList.of(b)) + def leftNel[A, B](a: A): IorNel[A, B] = left(NonEmptyList.of(a)) + def bothNel[A, B](a: A, b: B): IorNel[A, B] = Ior.Both(NonEmptyList.of(a), NonEmptyList.of(b)) /** * Create an `Ior` from two Options if at least one of them is defined. diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 396f22908d..9e4eeedb62 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -3,6 +3,7 @@ package cats package object data { type NonEmptyStream[A] = OneAnd[Stream, A] type ValidatedNel[+E, +A] = Validated[NonEmptyList[E], A] + type IorNel[+B, +A] = Ior[NonEmptyList[B], NonEmptyList[A]] def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = OneAnd(head, tail) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala new file mode 100644 index 0000000000..b07f28e11a --- /dev/null +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -0,0 +1,115 @@ +package cats.syntax + +import cats.data.{Ior, IorNel} + +trait IorSyntax { + implicit def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) + implicit def catsSyntaxIorId[A, B](list: List[IorNel[A, B]]): IorNelListOps[A, B] = + new IorNelListOps(list) +} + +final class IorIdOps[A](val a: A) extends AnyVal { + /** + * Wrap a value in `Ior.Right`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".rightIor[String] + * res0: Ior[String, String] = Ior.Right("hello") + * }}} + */ + def rightIor[B]: Ior[B, A] = Ior.right(a) + + /** + * Wrap a value in `Ior.Left`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".leftIor[String] + * res0: Ior[String, String] = Ior.Left("hello") + * }}} + */ + def leftIor[B]: Ior[A, B] = Ior.left(a) + + /** + * Wrap a value in the right side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".putRightIor[String]("error") + * res0: Ior[String, String] = Ior.Both("error", "hello") + * }}} + */ + def putRightIor[B](left: B): Ior[B, A] = Ior.both(left, a) + + /** + * Wrap a value in the left side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "I got it wrong".putLeftIor[String]("hello") + * res0: Ior[String, String] = Ior.Both("I got it wrong", "hello") + * }}} + */ + def putLeftIor[B](right: B): Ior[A, B] = Ior.both(a, right) + + /** + * Wrap a value in a NonEmptyList in `Ior.Right`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".rightNelIor[String] + * res0: IorNel[String, String] = Ior.Right(NonEmptyList("hello", Nil)) + * }}} + */ + def rightNelIor[B]: IorNel[B, A] = Ior.rightNel(a) + + /** + * Wrap a value in a NonEmptyList in `Ior.Left`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".leftNelIor[String] + * res0: IorNel[String, String] = Ior.Left(NonEmptyList("hello", Nil)) + * }}} + */ + def leftNelIor[B]: IorNel[A, B] = Ior.leftNel(a) + + /** + * Wrap a value in a NonEmptyList in the right side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "hello".putRightNelIor[String]("error") + * res0: IorNel[String, String] = Ior.Both(NonEmptyList("error", Nil), NonEmptyList("hello", Nil)) + * }}} + */ + def putRightNelIor[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) + + /** + * Wrap a value in a NonEmptyList in the left side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> "I got it wrong".putLeftNelIor[String]("hello") + * res0: IorNel[String, String] = Ior.Both(NonEmptyList("I got it wrong", Nil), NonEmptyList("hello", Nil)) + * }}} + */ + def putLeftNelIor[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) +} + + +final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { + + def reduceIorNel: IorNel[A, B] = list reduce (_ append _) + + def reduceOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) +} diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index bc9962eac5..dfa9ebd256 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -22,6 +22,7 @@ package object syntax { object functorFilter extends FunctorFilterSyntax object group extends GroupSyntax object invariant extends InvariantSyntax + object ior extends IorSyntax object list extends ListSyntax object monadCombine extends MonadCombineSyntax object monadError extends MonadErrorSyntax From 756d1ed83e51153338ad7645a7a3a932129c8286 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 11:32:01 -0500 Subject: [PATCH 02/17] Removed examples on ior syntax comments --- core/src/main/scala/cats/syntax/ior.scala | 65 +++-------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index b07f28e11a..6d5c7b78f9 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -11,97 +11,41 @@ trait IorSyntax { final class IorIdOps[A](val a: A) extends AnyVal { /** * Wrap a value in `Ior.Right`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".rightIor[String] - * res0: Ior[String, String] = Ior.Right("hello") - * }}} */ def rightIor[B]: Ior[B, A] = Ior.right(a) /** * Wrap a value in `Ior.Left`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".leftIor[String] - * res0: Ior[String, String] = Ior.Left("hello") - * }}} */ def leftIor[B]: Ior[A, B] = Ior.left(a) /** * Wrap a value in the right side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".putRightIor[String]("error") - * res0: Ior[String, String] = Ior.Both("error", "hello") - * }}} */ def putRightIor[B](left: B): Ior[B, A] = Ior.both(left, a) /** * Wrap a value in the left side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "I got it wrong".putLeftIor[String]("hello") - * res0: Ior[String, String] = Ior.Both("I got it wrong", "hello") - * }}} */ def putLeftIor[B](right: B): Ior[A, B] = Ior.both(a, right) /** * Wrap a value in a NonEmptyList in `Ior.Right`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".rightNelIor[String] - * res0: IorNel[String, String] = Ior.Right(NonEmptyList("hello", Nil)) - * }}} */ def rightNelIor[B]: IorNel[B, A] = Ior.rightNel(a) /** * Wrap a value in a NonEmptyList in `Ior.Left`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".leftNelIor[String] - * res0: IorNel[String, String] = Ior.Left(NonEmptyList("hello", Nil)) - * }}} */ def leftNelIor[B]: IorNel[A, B] = Ior.leftNel(a) /** * Wrap a value in a NonEmptyList in the right side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "hello".putRightNelIor[String]("error") - * res0: IorNel[String, String] = Ior.Both(NonEmptyList("error", Nil), NonEmptyList("hello", Nil)) - * }}} */ def putRightNelIor[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) /** * Wrap a value in a NonEmptyList in the left side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> "I got it wrong".putLeftNelIor[String]("hello") - * res0: IorNel[String, String] = Ior.Both(NonEmptyList("I got it wrong", Nil), NonEmptyList("hello", Nil)) - * }}} */ def putLeftNelIor[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) } @@ -109,7 +53,10 @@ final class IorIdOps[A](val a: A) extends AnyVal { final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { - def reduceIorNel: IorNel[A, B] = list reduce (_ append _) + /** + * Returns single combined IorNel by reducing a list of IorNel + */ + def reduceToIorNel: IorNel[A, B] = list reduce (_ append _) - def reduceOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) -} + def reduceToOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) +} \ No newline at end of file From 4610791a3f03b57f3d893fc87957ceaad6350b75 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 11:32:26 -0500 Subject: [PATCH 03/17] Removed toValidatedNel functions --- core/src/main/scala/cats/data/Ior.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 24d65a5317..89b54cbbe9 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -50,8 +50,6 @@ sealed abstract class Ior[+A, +B] extends Product with Serializable { final def toEither: Either[A, B] = fold(Left(_), Right(_), (_, b) => Right(b)) final def toValidated: Validated[A, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b)) - final def toValidatedNel: ValidatedNel[A, B] = fold(Validated.invalidNel, Valid(_), (_, b) => Valid(b)) - final def toValidatedNel[C](implicit ev: A <:< NonEmptyList[C]): ValidatedNel[C, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b)) final def toOption: Option[B] = right final def toList: List[B] = right.toList From 50bf4a6e459c6ea99d3f23bd92c85563a217ea7f Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 11:33:23 -0500 Subject: [PATCH 04/17] Added syntax to list for IorNel and ValidatedNel --- core/src/main/scala/cats/syntax/all.scala | 1 + core/src/main/scala/cats/syntax/list.scala | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 00197e881f..44845bd32d 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -22,6 +22,7 @@ trait AllSyntax with FunctorFilterSyntax with GroupSyntax with InvariantSyntax + with IorSyntax with ListSyntax with MonadCombineSyntax with MonadErrorSyntax diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index 88defb39da..e9148650d5 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -1,7 +1,8 @@ package cats package syntax -import cats.data.NonEmptyList +import cats.data.Validated.{Invalid, Valid} +import cats.data.{Ior, IorNel, NonEmptyList, ValidatedNel} trait ListSyntax { implicit def catsSyntaxList[A](la: List[A]): ListOps[A] = new ListOps(la) @@ -9,4 +10,22 @@ trait ListSyntax { final class ListOps[A](val la: List[A]) extends AnyVal { def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) + + /** + * Returns a IorNel from a List + */ + def toRightIorNel[B](ifEmpty: => B): IorNel[B, A] = + toNel.fold[IorNel[B, A]](Ior.leftNel(ifEmpty))(Ior.right) + + /** + * Returns a IorNel from a List + */ + def toLeftIorNel[B](ifEmpty: => B): IorNel[A, B] = + toNel.fold[IorNel[A, B]](Ior.rightNel(ifEmpty))(Ior.left) + + /** + * Returns a ValidatedNel from a List + */ + def toValidatedNel[B](ifEmpty: => B): ValidatedNel[A, B] = + toNel.fold[ValidatedNel[A, B]](Valid(ifEmpty))(Invalid(_)) } From 3eb78f891e6651ad9ac02510918a4686c8e5c30e Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 11:33:42 -0500 Subject: [PATCH 05/17] Added test for toValidated function --- tests/src/test/scala/cats/tests/IorTests.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index ae8e4946af..c6ecbfe2f5 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -3,8 +3,8 @@ package tests import cats.data.Ior import cats.kernel.laws.GroupLaws -import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} import org.scalacheck.Arbitrary._ class IorTests extends CatsSuite { @@ -198,6 +198,12 @@ class IorTests extends CatsSuite { } } + test("toValidated consistent with right") { + forAll { (x: Int Ior String) => + x.toValidated.toOption should === (x.right) + } + } + test("getOrElse consistent with Option getOrElse") { forAll { (x: Int Ior String, default: String) => x.getOrElse(default) should === (x.toOption.getOrElse(default)) From 4350f57aa6fe4c9f89faf5c8f694b3eb090406f9 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 12:10:59 -0500 Subject: [PATCH 06/17] Added newline to end of ior.scala file --- core/src/main/scala/cats/syntax/ior.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index 6d5c7b78f9..462438b230 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -59,4 +59,4 @@ final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { def reduceToIorNel: IorNel[A, B] = list reduce (_ append _) def reduceToOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) -} \ No newline at end of file +} From edf746631d7e8cea06a05af27afa317dfce474a3 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 13:07:10 -0500 Subject: [PATCH 07/17] Added toIor functions to option syntax --- core/src/main/scala/cats/syntax/option.scala | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/option.scala b/core/src/main/scala/cats/syntax/option.scala index a824768611..26063e5fc1 100644 --- a/core/src/main/scala/cats/syntax/option.scala +++ b/core/src/main/scala/cats/syntax/option.scala @@ -1,7 +1,7 @@ package cats package syntax -import cats.data.{Validated, ValidatedNel} +import cats.data.{Ior, Validated, ValidatedNel} trait OptionSyntax { final def none[A]: Option[A] = Option.empty[A] @@ -112,6 +112,18 @@ final class OptionOps[A](val oa: Option[A]) extends AnyVal { */ def toValidNel[B](b: => B): ValidatedNel[B, A] = oa.fold[ValidatedNel[B, A]](Validated.invalidNel(b))(Validated.Valid(_)) + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Ior.Right]]. + * If the `Option` is `None`, wrap the provided `B` value in a [[cats.data.Ior.Left]] + */ + def toRightIor[B](b: => B): Ior[B, A] = oa.fold[Ior[B, A]](Ior.Left(b))(Ior.Right(_)) + + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Ior.Left]]. + * If the `Option` is `None`, wrap the provided `B` value in a [[cats.data.Ior.Right]] + */ + def toLeftIor[B](b: => B): Ior[A, B] = oa.fold[Ior[A, B]](Ior.Right(b))(Ior.Left(_)) + /** * If the `Option` is a `Some`, return its value. If the `Option` is `None`, * return the `empty` value for `Monoid[A]`. From 2b1894111b1a13d929a3d03b50b0346c0f6d0bce Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 13:08:24 -0500 Subject: [PATCH 08/17] Added fromIor to ValidatedFunctions and toIor function to Validated datatype --- core/src/main/scala/cats/data/Validated.scala | 10 ++++++++++ .../test/scala/cats/tests/ValidatedTests.scala | 16 +++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index c014b2bf35..65e9a35089 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -75,6 +75,11 @@ sealed abstract class Validated[+E, +A] extends Product with Serializable { */ def toOption: Option[A] = fold(_ => None, Some.apply) + /** + * Returns Valid values wrapped in Ior.Right, and None for Ior.Left values + */ + def toIor: Ior[E, A] = fold(Ior.left, Ior.right) + /** * Convert this value to a single element List if it is Valid, * otherwise return an empty List @@ -405,4 +410,9 @@ private[data] trait ValidatedFunctions { * the invalid of the `Validated` when the specified `Option` is `None`. */ def fromOption[A, B](o: Option[B], ifNone: => A): Validated[A, B] = o.fold(invalid[A, B](ifNone))(valid) + + /** + * Converts an `Ior[A, B]` to an `Validated[A, B]`. + */ + def fromIor[A, B](ior: Ior[A, B]): Validated[A, B] = ior.fold(invalid, valid, (_, b) => valid(b)) } diff --git a/tests/src/test/scala/cats/tests/ValidatedTests.scala b/tests/src/test/scala/cats/tests/ValidatedTests.scala index 7904f7a860..39eb130278 100644 --- a/tests/src/test/scala/cats/tests/ValidatedTests.scala +++ b/tests/src/test/scala/cats/tests/ValidatedTests.scala @@ -1,13 +1,13 @@ package cats package tests -import cats.data.{EitherT, NonEmptyList, Validated, ValidatedNel} -import cats.data.Validated.{Valid, Invalid} -import cats.laws.discipline.{BitraverseTests, TraverseTests, ApplicativeErrorTests, SerializableTests, CartesianTests} +import cats.data._ +import cats.data.Validated.{Invalid, Valid} +import cats.laws.discipline.{ApplicativeErrorTests, BitraverseTests, CartesianTests, SerializableTests, TraverseTests} import org.scalacheck.Arbitrary._ -import cats.laws.discipline.{SemigroupKTests} +import cats.laws.discipline.SemigroupKTests import cats.laws.discipline.arbitrary._ -import cats.kernel.laws.{OrderLaws, GroupLaws} +import cats.kernel.laws.{GroupLaws, OrderLaws} import scala.util.Try @@ -187,6 +187,12 @@ class ValidatedTests extends CatsSuite { } } + test("fromIor consistent with Ior.toValidated"){ + forAll { (i: Ior[String, Int], s: String) => + Validated.fromIor(i) should === (i.toValidated) + } + } + test("isValid after combine, iff both are valid") { forAll { (lhs: Validated[Int, String], rhs: Validated[Int, String]) => lhs.combine(rhs).isValid should === (lhs.isValid && rhs.isValid) From 54fb5c83d186d6e2943f19c7d8680d9e8765c69b Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 15:59:26 -0500 Subject: [PATCH 09/17] Corrected error on duplicated implicit defs on syntax.ior.scala --- core/src/main/scala/cats/syntax/ior.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index 462438b230..d6e33c5891 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -4,7 +4,7 @@ import cats.data.{Ior, IorNel} trait IorSyntax { implicit def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) - implicit def catsSyntaxIorId[A, B](list: List[IorNel[A, B]]): IorNelListOps[A, B] = + implicit def catsSyntaxListIorNel[A, B](list: List[IorNel[A, B]]): IorNelListOps[A, B] = new IorNelListOps(list) } From 831e32faa705d7db9d326d9c27117dcbd379a45c Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 19:10:40 -0500 Subject: [PATCH 10/17] Added tests for new functions in Validated and Ior --- core/src/main/scala/cats/syntax/option.scala | 28 +++++++++++++++++++ .../src/test/scala/cats/tests/IorTests.scala | 20 ++++++++++++- .../scala/cats/tests/ValidatedTests.scala | 6 ++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/option.scala b/core/src/main/scala/cats/syntax/option.scala index 26063e5fc1..25dbbffb07 100644 --- a/core/src/main/scala/cats/syntax/option.scala +++ b/core/src/main/scala/cats/syntax/option.scala @@ -115,12 +115,40 @@ final class OptionOps[A](val oa: Option[A]) extends AnyVal { /** * If the `Option` is a `Some`, return its value in a [[cats.data.Ior.Right]]. * If the `Option` is `None`, wrap the provided `B` value in a [[cats.data.Ior.Left]] + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> val result1: Option[Int] = Some(3) + * scala> result1.toRightIor("error!") + * res0: Ior[String, Int] = Right(3) + * + * scala> val result2: Option[Int] = None + * scala> result2.toRightIor("error!") + * res1: Ior[String, Int] = Left(error!) + * }}} */ def toRightIor[B](b: => B): Ior[B, A] = oa.fold[Ior[B, A]](Ior.Left(b))(Ior.Right(_)) /** * If the `Option` is a `Some`, return its value in a [[cats.data.Ior.Left]]. * If the `Option` is `None`, wrap the provided `B` value in a [[cats.data.Ior.Right]] + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> val result1: Option[String] = Some("error!") + * scala> result1.toLeftIor(3) + * res0: Ior[String, Int] = Left(error!) + * + * scala> val result2: Option[String] = None + * scala> result2.toLeftIor(3) + * res1: Ior[String, Int] = Right(3) + * }}} */ def toLeftIor[B](b: => B): Ior[A, B] = oa.fold[Ior[A, B]](Ior.Right(b))(Ior.Left(_)) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index c6ecbfe2f5..8eb3458571 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.data.Ior +import cats.data.{Ior, NonEmptyList} import cats.kernel.laws.GroupLaws import cats.laws.discipline.arbitrary._ import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} @@ -204,6 +204,24 @@ class IorTests extends CatsSuite { } } + test("rightNel") { + forAll { (x: Int) => + Ior.rightNel(x).right should === (Some(NonEmptyList.of(x))) + } + } + + test("leftNel") { + forAll { (x: String) => + Ior.leftNel(x).left should === (Some(NonEmptyList.of(x))) + } + } + + test("bothNel") { + forAll { (x: Int, y: String) => + Ior.bothNel(y, x).onlyBoth should === (Some((NonEmptyList.of(y), NonEmptyList.of(x)))) + } + } + test("getOrElse consistent with Option getOrElse") { forAll { (x: Int Ior String, default: String) => x.getOrElse(default) should === (x.toOption.getOrElse(default)) diff --git a/tests/src/test/scala/cats/tests/ValidatedTests.scala b/tests/src/test/scala/cats/tests/ValidatedTests.scala index 39eb130278..b89b632401 100644 --- a/tests/src/test/scala/cats/tests/ValidatedTests.scala +++ b/tests/src/test/scala/cats/tests/ValidatedTests.scala @@ -193,6 +193,12 @@ class ValidatedTests extends CatsSuite { } } + test("toIor then fromEither is identity") { + forAll { (v: Validated[String, Int]) => + Validated.fromIor(v.toIor) should === (v) + } + } + test("isValid after combine, iff both are valid") { forAll { (lhs: Validated[Int, String], rhs: Validated[Int, String]) => lhs.combine(rhs).isValid should === (lhs.isValid && rhs.isValid) From 9e71a77447c9b812ef09078348033b1e7066913e Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 20:22:59 -0500 Subject: [PATCH 11/17] Added examples to list syntax functions --- core/src/main/scala/cats/syntax/list.scala | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index e9148650d5..75dae7e861 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -9,16 +9,62 @@ trait ListSyntax { } final class ListOps[A](val la: List[A]) extends AnyVal { + + /** + * Returns an Option of NonEmptyList from a List + * + * Example: + * {{{ + * scala> import cats.data.NonEmptyList + * scala> import cats.implicits._ + * + * scala> val result1: List[Int] = List(1, 2) + * scala> result1.toNel + * res0: Option[NonEmptyList[Int]] = Some(NonEmptyList(1, List(2))) + * + * scala> val result2: List[Int] = List.empty[Int] + * scala> result2.toNel + * res1: Option[NonEmptyList[Int]] = None + * }}} + */ def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) /** * Returns a IorNel from a List + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> val result1: List[Int] = List(1, 2) + * scala> result1.toRightIorNel("error!") + * res0: IorNel[String, Int] = Right(NonEmptyList(1, List(2))) + * + * scala> val result2: List[Int] = List.empty[Int] + * scala> result2.toRightIorNel("error!") + * res1: IorNel[String, Int] = Left(NonEmptyList(error!)) + * }}} */ def toRightIorNel[B](ifEmpty: => B): IorNel[B, A] = toNel.fold[IorNel[B, A]](Ior.leftNel(ifEmpty))(Ior.right) /** * Returns a IorNel from a List + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> val result1: List[String] = List("error 1", "error 2") + * scala> result1.toLeftIorNel(1) + * res0: IorNel[String, Int] = Left(NonEmptyList(error 1, List(error 2))) + * + * scala> val result2: List[String] = List.empty[String] + * scala> result2.toLeftIorNel(1) + * res1: IorNel[String, Int] = Right(NonEmptyList(1)) + * }}} */ def toLeftIorNel[B](ifEmpty: => B): IorNel[A, B] = toNel.fold[IorNel[A, B]](Ior.rightNel(ifEmpty))(Ior.left) From 6924628d2cc950ad7c63a9a8d57312e49a11b2be Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Feb 2017 22:56:52 -0500 Subject: [PATCH 12/17] Corrected errors on list syntax examples --- core/src/main/scala/cats/syntax/list.scala | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index 75dae7e861..65c5e2a23d 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -20,7 +20,7 @@ final class ListOps[A](val la: List[A]) extends AnyVal { * * scala> val result1: List[Int] = List(1, 2) * scala> result1.toNel - * res0: Option[NonEmptyList[Int]] = Some(NonEmptyList(1, List(2))) + * res0: Option[NonEmptyList[Int]] = Some(NonEmptyList(1, 2)) * * scala> val result2: List[Int] = List.empty[Int] * scala> result2.toNel @@ -39,7 +39,7 @@ final class ListOps[A](val la: List[A]) extends AnyVal { * * scala> val result1: List[Int] = List(1, 2) * scala> result1.toRightIorNel("error!") - * res0: IorNel[String, Int] = Right(NonEmptyList(1, List(2))) + * res0: IorNel[String, Int] = Right(NonEmptyList(1, 2)) * * scala> val result2: List[Int] = List.empty[Int] * scala> result2.toRightIorNel("error!") @@ -59,7 +59,7 @@ final class ListOps[A](val la: List[A]) extends AnyVal { * * scala> val result1: List[String] = List("error 1", "error 2") * scala> result1.toLeftIorNel(1) - * res0: IorNel[String, Int] = Left(NonEmptyList(error 1, List(error 2))) + * res0: IorNel[String, Int] = Left(NonEmptyList(error 1, error 2)) * * scala> val result2: List[String] = List.empty[String] * scala> result2.toLeftIorNel(1) @@ -71,6 +71,20 @@ final class ListOps[A](val la: List[A]) extends AnyVal { /** * Returns a ValidatedNel from a List + * + * Example: + * {{{ + * scala> import cats.data.ValidatedNel + * scala> import cats.implicits._ + * + * scala> val result1: List[String] = List("error 1", "error 2") + * scala> result1.toValidatedNel(1) + * res0: ValidatedNel[String, Int] = Invalid(NonEmptyList(error 1, error 2)) + * + * scala> val result2: List[String] = List.empty[String] + * scala> result2.toValidatedNel(1) + * res1: ValidatedNel[String, Int] = Valid(1) + * }}} */ def toValidatedNel[B](ifEmpty: => B): ValidatedNel[A, B] = toNel.fold[ValidatedNel[A, B]](Valid(ifEmpty))(Invalid(_)) From f03ab7d0499ef10f93a62a95e1f09ccf01e27cb3 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Mon, 20 Feb 2017 00:15:09 -0500 Subject: [PATCH 13/17] Added corrected examples to ior syntax --- core/src/main/scala/cats/syntax/ior.scala | 96 +++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index d6e33c5891..2b2c773b67 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -11,41 +11,113 @@ trait IorSyntax { final class IorIdOps[A](val a: A) extends AnyVal { /** * Wrap a value in `Ior.Right`. + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> "hello".rightIor[String] + * res0: Ior[String, String] = Right(hello) + * }}} */ def rightIor[B]: Ior[B, A] = Ior.right(a) /** * Wrap a value in `Ior.Left`. + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> "error".leftIor[String] + * res0: Ior[String, String] = Left(error) + * }}} */ def leftIor[B]: Ior[A, B] = Ior.left(a) /** * Wrap a value in the right side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> "hello".putRightIor("error") + * res0: Ior[String, String] = Both(error,hello) + * }}} */ def putRightIor[B](left: B): Ior[B, A] = Ior.both(left, a) /** * Wrap a value in the left side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.data.Ior + * scala> import cats.implicits._ + * + * scala> "error".putLeftIor("hello") + * res0: Ior[String, String] = Both(error,hello) + * }}} */ def putLeftIor[B](right: B): Ior[A, B] = Ior.both(a, right) /** * Wrap a value in a NonEmptyList in `Ior.Right`. + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> "hello".rightNelIor[String] + * res0: IorNel[String, String] = Right(NonEmptyList(hello)) + * }}} */ def rightNelIor[B]: IorNel[B, A] = Ior.rightNel(a) /** * Wrap a value in a NonEmptyList in `Ior.Left`. + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> "error".leftNelIor[String] + * res0: IorNel[String, String] = Left(NonEmptyList(error)) + * }}} */ def leftNelIor[B]: IorNel[A, B] = Ior.leftNel(a) /** * Wrap a value in a NonEmptyList in the right side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> "hello".putRightNelIor[String]("error") + * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) + * }}} */ def putRightNelIor[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) /** * Wrap a value in a NonEmptyList in the left side of `Ior.Both`. + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> "I got it wrong".putLeftNelIor[String]("hello") + * res0: IorNel[String, String] = Both(NonEmptyList(I got it wrong),NonEmptyList(hello)) + * }}} */ def putLeftNelIor[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) } @@ -55,8 +127,32 @@ final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { /** * Returns single combined IorNel by reducing a list of IorNel + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> List("hello".rightNelIor[String], "error".leftNelIor[String]).reduceToIorNel + * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) + * }}} */ def reduceToIorNel: IorNel[A, B] = list reduce (_ append _) + /** + * Returns an Option of a single combined IorNel by reducing a list of IorNel + * + * Example: + * {{{ + * scala> import cats.data.IorNel + * scala> import cats.implicits._ + * + * scala> List("hello".rightNelIor[String], "error".leftNelIor[String]).reduceToOptionIorNel + * res0: Option[IorNel[String, String]] = Some(Both(NonEmptyList(error),NonEmptyList(hello))) + * + * scala> List.empty[IorNel[String, String]].reduceToOptionIorNel + * res1: Option[IorNel[String, String]] = None + * }}} + */ def reduceToOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) } From 989de6ca8a8030d251cab246ae6ad050dbacda28 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Mon, 20 Feb 2017 09:42:12 -0500 Subject: [PATCH 14/17] Corrected names for IorNel syntax functions --- core/src/main/scala/cats/syntax/ior.scala | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index 2b2c773b67..55bfc4ead5 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -73,11 +73,11 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> "hello".rightNelIor[String] + * scala> "hello".rightIorNel[String] * res0: IorNel[String, String] = Right(NonEmptyList(hello)) * }}} */ - def rightNelIor[B]: IorNel[B, A] = Ior.rightNel(a) + def rightIorNel[B]: IorNel[B, A] = Ior.rightNel(a) /** * Wrap a value in a NonEmptyList in `Ior.Left`. @@ -87,11 +87,11 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> "error".leftNelIor[String] + * scala> "error".leftIorNel[String] * res0: IorNel[String, String] = Left(NonEmptyList(error)) * }}} */ - def leftNelIor[B]: IorNel[A, B] = Ior.leftNel(a) + def leftIorNel[B]: IorNel[A, B] = Ior.leftNel(a) /** * Wrap a value in a NonEmptyList in the right side of `Ior.Both`. @@ -101,11 +101,11 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> "hello".putRightNelIor[String]("error") + * scala> "hello".putRightIorNel[String]("error") * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) * }}} */ - def putRightNelIor[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) + def putRightIorNel[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) /** * Wrap a value in a NonEmptyList in the left side of `Ior.Both`. @@ -115,11 +115,11 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> "I got it wrong".putLeftNelIor[String]("hello") + * scala> "I got it wrong".putLeftIorNel[String]("hello") * res0: IorNel[String, String] = Both(NonEmptyList(I got it wrong),NonEmptyList(hello)) * }}} */ - def putLeftNelIor[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) + def putLeftIorNel[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) } @@ -133,7 +133,7 @@ final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> List("hello".rightNelIor[String], "error".leftNelIor[String]).reduceToIorNel + * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToIorNel * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) * }}} */ @@ -147,7 +147,7 @@ final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { * scala> import cats.data.IorNel * scala> import cats.implicits._ * - * scala> List("hello".rightNelIor[String], "error".leftNelIor[String]).reduceToOptionIorNel + * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToOptionIorNel * res0: Option[IorNel[String, String]] = Some(Both(NonEmptyList(error),NonEmptyList(hello))) * * scala> List.empty[IorNel[String, String]].reduceToOptionIorNel From 09227735538a4a9587caec655ffd9f601402dc10 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Wed, 1 Mar 2017 23:16:29 -0500 Subject: [PATCH 15/17] Redifined the IorNel type alias --- core/src/main/scala/cats/data/Ior.scala | 8 ++--- core/src/main/scala/cats/data/Validated.scala | 6 ++-- core/src/main/scala/cats/data/package.scala | 2 +- core/src/main/scala/cats/syntax/ior.scala | 35 +++++++++++-------- core/src/main/scala/cats/syntax/list.scala | 28 +++------------ .../src/test/scala/cats/tests/IorTests.scala | 8 ++--- .../scala/cats/tests/ValidatedTests.scala | 2 +- 7 files changed, 37 insertions(+), 52 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 89b54cbbe9..587838245b 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -105,7 +105,7 @@ sealed abstract class Ior[+A, +B] extends Product with Serializable { fold(identity, ev, (_, b) => ev(b)) // scalastyle:off cyclomatic.complexity - final def append[AA >: A, BB >: B](that: AA Ior BB)(implicit AA: Semigroup[AA], BB: Semigroup[BB]): AA Ior BB = this match { + final def combine[AA >: A, BB >: B](that: AA Ior BB)(implicit AA: Semigroup[AA], BB: Semigroup[BB]): AA Ior BB = this match { case Ior.Left(a1) => that match { case Ior.Left(a2) => Ior.Left(AA.combine(a1, a2)) case Ior.Right(b2) => Ior.Both(a1, b2) @@ -153,7 +153,7 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { } implicit def catsDataSemigroupForIor[A: Semigroup, B: Semigroup]: Semigroup[Ior[A, B]] = new Semigroup[Ior[A, B]] { - def combine(x: Ior[A, B], y: Ior[A, B]) = x.append(y) + def combine(x: Ior[A, B], y: Ior[A, B]) = x.combine(y) } implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] = new Monad[A Ior ?] { @@ -201,9 +201,9 @@ private[data] sealed trait IorFunctions { def left[A, B](a: A): A Ior B = Ior.Left(a) def right[A, B](b: B): A Ior B = Ior.Right(b) def both[A, B](a: A, b: B): A Ior B = Ior.Both(a, b) - def rightNel[A, B](b: B): IorNel[A, B] = right(NonEmptyList.of(b)) + def rightNel[A, B](b: B): IorNel[A, B] = right(b) def leftNel[A, B](a: A): IorNel[A, B] = left(NonEmptyList.of(a)) - def bothNel[A, B](a: A, b: B): IorNel[A, B] = Ior.Both(NonEmptyList.of(a), NonEmptyList.of(b)) + def bothNel[A, B](a: A, b: B): IorNel[A, B] = Ior.Both(NonEmptyList.of(a), b) /** * Create an `Ior` from two Options if at least one of them is defined. diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index 65e9a35089..086f823b5c 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -401,18 +401,18 @@ private[data] trait ValidatedFunctions { } /** - * Converts an `Either[A, B]` to an `Validated[A, B]`. + * Converts an `Either[A, B]` to a `Validated[A, B]`. */ def fromEither[A, B](e: Either[A, B]): Validated[A, B] = e.fold(invalid, valid) /** - * Converts an `Option[B]` to an `Validated[A, B]`, where the provided `ifNone` values is returned on + * Converts an `Option[B]` to a `Validated[A, B]`, where the provided `ifNone` values is returned on * the invalid of the `Validated` when the specified `Option` is `None`. */ def fromOption[A, B](o: Option[B], ifNone: => A): Validated[A, B] = o.fold(invalid[A, B](ifNone))(valid) /** - * Converts an `Ior[A, B]` to an `Validated[A, B]`. + * Converts an `Ior[A, B]` to a `Validated[A, B]`. */ def fromIor[A, B](ior: Ior[A, B]): Validated[A, B] = ior.fold(invalid, valid, (_, b) => valid(b)) } diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 9e4eeedb62..e81751b06c 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -3,7 +3,7 @@ package cats package object data { type NonEmptyStream[A] = OneAnd[Stream, A] type ValidatedNel[+E, +A] = Validated[NonEmptyList[E], A] - type IorNel[+B, +A] = Ior[NonEmptyList[B], NonEmptyList[A]] + type IorNel[+B, +A] = Ior[NonEmptyList[B], A] def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = OneAnd(head, tail) diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index 55bfc4ead5..7c44029767 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -1,6 +1,6 @@ package cats.syntax -import cats.data.{Ior, IorNel} +import cats.data.{Ior, IorNel, NonEmptyList} trait IorSyntax { implicit def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) @@ -74,7 +74,7 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.implicits._ * * scala> "hello".rightIorNel[String] - * res0: IorNel[String, String] = Right(NonEmptyList(hello)) + * res0: IorNel[String, String] = Right(hello) * }}} */ def rightIorNel[B]: IorNel[B, A] = Ior.rightNel(a) @@ -102,7 +102,7 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.implicits._ * * scala> "hello".putRightIorNel[String]("error") - * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) + * res0: IorNel[String, String] = Both(NonEmptyList(error),hello) * }}} */ def putRightIorNel[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) @@ -116,7 +116,7 @@ final class IorIdOps[A](val a: A) extends AnyVal { * scala> import cats.implicits._ * * scala> "I got it wrong".putLeftIorNel[String]("hello") - * res0: IorNel[String, String] = Both(NonEmptyList(I got it wrong),NonEmptyList(hello)) + * res0: IorNel[String, String] = Both(NonEmptyList(I got it wrong),hello) * }}} */ def putLeftIorNel[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) @@ -126,33 +126,38 @@ final class IorIdOps[A](val a: A) extends AnyVal { final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { /** - * Returns single combined IorNel by reducing a list of IorNel + * Returns single combined Ior by reducing a list of IorNel * * Example: * {{{ - * scala> import cats.data.IorNel + * scala> import cats.data.Ior + * scala> import cats.data.NonEmptyList * scala> import cats.implicits._ * - * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToIorNel - * res0: IorNel[String, String] = Both(NonEmptyList(error),NonEmptyList(hello)) + * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToIor + * res0: Ior[NonEmptyList[String], NonEmptyList[String]] = Both(NonEmptyList(error),NonEmptyList(hello)) * }}} */ - def reduceToIorNel: IorNel[A, B] = list reduce (_ append _) + def reduceToIor: Ior[NonEmptyList[A], NonEmptyList[B]] = + list.map(_.map(NonEmptyList(_, Nil))).reduce(_ combine _) /** - * Returns an Option of a single combined IorNel by reducing a list of IorNel + * Returns an Option of a single combined Ior by reducing a list of IorNel * * Example: * {{{ + * scala> import cats.data.Ior * scala> import cats.data.IorNel + * scala> import cats.data.NonEmptyList * scala> import cats.implicits._ * - * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToOptionIorNel - * res0: Option[IorNel[String, String]] = Some(Both(NonEmptyList(error),NonEmptyList(hello))) + * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToOptionIor + * res0: Option[Ior[NonEmptyList[String], NonEmptyList[String]]] = Some(Both(NonEmptyList(error),NonEmptyList(hello))) * - * scala> List.empty[IorNel[String, String]].reduceToOptionIorNel - * res1: Option[IorNel[String, String]] = None + * scala> List.empty[IorNel[String, String]].reduceToOptionIor + * res1: Option[Ior[NonEmptyList[String], NonEmptyList[String]]] = None * }}} */ - def reduceToOptionIorNel: Option[IorNel[A, B]] = list reduceOption (_ append _) + def reduceToOptionIor: Option[Ior[NonEmptyList[A], NonEmptyList[B]]] = + list.map(_.map(NonEmptyList(_, Nil))) reduceOption (_ combine _) } diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index 65c5e2a23d..f49aa79a01 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -29,26 +29,6 @@ final class ListOps[A](val la: List[A]) extends AnyVal { */ def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) - /** - * Returns a IorNel from a List - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> val result1: List[Int] = List(1, 2) - * scala> result1.toRightIorNel("error!") - * res0: IorNel[String, Int] = Right(NonEmptyList(1, 2)) - * - * scala> val result2: List[Int] = List.empty[Int] - * scala> result2.toRightIorNel("error!") - * res1: IorNel[String, Int] = Left(NonEmptyList(error!)) - * }}} - */ - def toRightIorNel[B](ifEmpty: => B): IorNel[B, A] = - toNel.fold[IorNel[B, A]](Ior.leftNel(ifEmpty))(Ior.right) - /** * Returns a IorNel from a List * @@ -58,15 +38,15 @@ final class ListOps[A](val la: List[A]) extends AnyVal { * scala> import cats.implicits._ * * scala> val result1: List[String] = List("error 1", "error 2") - * scala> result1.toLeftIorNel(1) + * scala> result1.toIorNel(1) * res0: IorNel[String, Int] = Left(NonEmptyList(error 1, error 2)) * * scala> val result2: List[String] = List.empty[String] - * scala> result2.toLeftIorNel(1) - * res1: IorNel[String, Int] = Right(NonEmptyList(1)) + * scala> result2.toIorNel(1) + * res1: IorNel[String, Int] = Right(1) * }}} */ - def toLeftIorNel[B](ifEmpty: => B): IorNel[A, B] = + def toIorNel[B](ifEmpty: => B): IorNel[A, B] = toNel.fold[IorNel[A, B]](Ior.rightNel(ifEmpty))(Ior.left) /** diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 8eb3458571..db2f2cf029 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -155,13 +155,13 @@ class IorTests extends CatsSuite { test("append left") { forAll { (i: Int Ior String, j: Int Ior String) => - i.append(j).left should === (i.left.map(_ + j.left.getOrElse(0)).orElse(j.left)) + i.combine(j).left should === (i.left.map(_ + j.left.getOrElse(0)).orElse(j.left)) } } test("append right") { forAll { (i: Int Ior String, j: Int Ior String) => - i.append(j).right should === (i.right.map(_ + j.right.getOrElse("")).orElse(j.right)) + i.combine(j).right should === (i.right.map(_ + j.right.getOrElse("")).orElse(j.right)) } } @@ -206,7 +206,7 @@ class IorTests extends CatsSuite { test("rightNel") { forAll { (x: Int) => - Ior.rightNel(x).right should === (Some(NonEmptyList.of(x))) + Ior.rightNel(x).right should === (Some(x)) } } @@ -218,7 +218,7 @@ class IorTests extends CatsSuite { test("bothNel") { forAll { (x: Int, y: String) => - Ior.bothNel(y, x).onlyBoth should === (Some((NonEmptyList.of(y), NonEmptyList.of(x)))) + Ior.bothNel(y, x).onlyBoth should === (Some((NonEmptyList.of(y), x))) } } diff --git a/tests/src/test/scala/cats/tests/ValidatedTests.scala b/tests/src/test/scala/cats/tests/ValidatedTests.scala index b89b632401..ed248ec9fa 100644 --- a/tests/src/test/scala/cats/tests/ValidatedTests.scala +++ b/tests/src/test/scala/cats/tests/ValidatedTests.scala @@ -188,7 +188,7 @@ class ValidatedTests extends CatsSuite { } test("fromIor consistent with Ior.toValidated"){ - forAll { (i: Ior[String, Int], s: String) => + forAll { (i: Ior[String, Int]) => Validated.fromIor(i) should === (i.toValidated) } } From d650b09d8a8fbaaa7f41ce2c134c8264080f5266 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Wed, 1 Mar 2017 23:39:56 -0500 Subject: [PATCH 16/17] Fixed test descriptions on IorTests --- tests/src/test/scala/cats/tests/IorTests.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index db2f2cf029..17b358e03a 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -153,13 +153,13 @@ class IorTests extends CatsSuite { } } - test("append left") { + test("combine left") { forAll { (i: Int Ior String, j: Int Ior String) => i.combine(j).left should === (i.left.map(_ + j.left.getOrElse(0)).orElse(j.left)) } } - test("append right") { + test("combine right") { forAll { (i: Int Ior String, j: Int Ior String) => i.combine(j).right should === (i.right.map(_ + j.right.getOrElse("")).orElse(j.right)) } From ef82db6cd661cc361557d5315e6871e950d30b7f Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Fri, 10 Mar 2017 21:01:44 -0500 Subject: [PATCH 17/17] Removed some functions from ior syntax object, deleted functions from list syntax object --- core/src/main/scala/cats/data/Ior.scala | 3 +- core/src/main/scala/cats/syntax/ior.scala | 128 +----------------- core/src/main/scala/cats/syntax/list.scala | 43 +----- .../src/test/scala/cats/tests/IorTests.scala | 6 - 4 files changed, 3 insertions(+), 177 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 587838245b..d62a7e51b6 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -201,9 +201,8 @@ private[data] sealed trait IorFunctions { def left[A, B](a: A): A Ior B = Ior.Left(a) def right[A, B](b: B): A Ior B = Ior.Right(b) def both[A, B](a: A, b: B): A Ior B = Ior.Both(a, b) - def rightNel[A, B](b: B): IorNel[A, B] = right(b) def leftNel[A, B](a: A): IorNel[A, B] = left(NonEmptyList.of(a)) - def bothNel[A, B](a: A, b: B): IorNel[A, B] = Ior.Both(NonEmptyList.of(a), b) + def bothNel[A, B](a: A, b: B): IorNel[A, B] = both(NonEmptyList.of(a), b) /** * Create an `Ior` from two Options if at least one of them is defined. diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index 7c44029767..bc8bdfacba 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -1,11 +1,9 @@ package cats.syntax -import cats.data.{Ior, IorNel, NonEmptyList} +import cats.data.Ior trait IorSyntax { implicit def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) - implicit def catsSyntaxListIorNel[A, B](list: List[IorNel[A, B]]): IorNelListOps[A, B] = - new IorNelListOps(list) } final class IorIdOps[A](val a: A) extends AnyVal { @@ -36,128 +34,4 @@ final class IorIdOps[A](val a: A) extends AnyVal { * }}} */ def leftIor[B]: Ior[A, B] = Ior.left(a) - - /** - * Wrap a value in the right side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.data.Ior - * scala> import cats.implicits._ - * - * scala> "hello".putRightIor("error") - * res0: Ior[String, String] = Both(error,hello) - * }}} - */ - def putRightIor[B](left: B): Ior[B, A] = Ior.both(left, a) - - /** - * Wrap a value in the left side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.data.Ior - * scala> import cats.implicits._ - * - * scala> "error".putLeftIor("hello") - * res0: Ior[String, String] = Both(error,hello) - * }}} - */ - def putLeftIor[B](right: B): Ior[A, B] = Ior.both(a, right) - - /** - * Wrap a value in a NonEmptyList in `Ior.Right`. - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> "hello".rightIorNel[String] - * res0: IorNel[String, String] = Right(hello) - * }}} - */ - def rightIorNel[B]: IorNel[B, A] = Ior.rightNel(a) - - /** - * Wrap a value in a NonEmptyList in `Ior.Left`. - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> "error".leftIorNel[String] - * res0: IorNel[String, String] = Left(NonEmptyList(error)) - * }}} - */ - def leftIorNel[B]: IorNel[A, B] = Ior.leftNel(a) - - /** - * Wrap a value in a NonEmptyList in the right side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> "hello".putRightIorNel[String]("error") - * res0: IorNel[String, String] = Both(NonEmptyList(error),hello) - * }}} - */ - def putRightIorNel[B](left: B): IorNel[B, A] = Ior.bothNel(left, a) - - /** - * Wrap a value in a NonEmptyList in the left side of `Ior.Both`. - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> "I got it wrong".putLeftIorNel[String]("hello") - * res0: IorNel[String, String] = Both(NonEmptyList(I got it wrong),hello) - * }}} - */ - def putLeftIorNel[B](right: B): IorNel[A, B] = Ior.bothNel(a, right) -} - - -final class IorNelListOps[A, B](val list: List[IorNel[A, B]]) extends AnyVal { - - /** - * Returns single combined Ior by reducing a list of IorNel - * - * Example: - * {{{ - * scala> import cats.data.Ior - * scala> import cats.data.NonEmptyList - * scala> import cats.implicits._ - * - * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToIor - * res0: Ior[NonEmptyList[String], NonEmptyList[String]] = Both(NonEmptyList(error),NonEmptyList(hello)) - * }}} - */ - def reduceToIor: Ior[NonEmptyList[A], NonEmptyList[B]] = - list.map(_.map(NonEmptyList(_, Nil))).reduce(_ combine _) - - /** - * Returns an Option of a single combined Ior by reducing a list of IorNel - * - * Example: - * {{{ - * scala> import cats.data.Ior - * scala> import cats.data.IorNel - * scala> import cats.data.NonEmptyList - * scala> import cats.implicits._ - * - * scala> List("hello".rightIorNel[String], "error".leftIorNel[String]).reduceToOptionIor - * res0: Option[Ior[NonEmptyList[String], NonEmptyList[String]]] = Some(Both(NonEmptyList(error),NonEmptyList(hello))) - * - * scala> List.empty[IorNel[String, String]].reduceToOptionIor - * res1: Option[Ior[NonEmptyList[String], NonEmptyList[String]]] = None - * }}} - */ - def reduceToOptionIor: Option[Ior[NonEmptyList[A], NonEmptyList[B]]] = - list.map(_.map(NonEmptyList(_, Nil))) reduceOption (_ combine _) } diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index f49aa79a01..5ff0b1980d 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -1,8 +1,7 @@ package cats package syntax -import cats.data.Validated.{Invalid, Valid} -import cats.data.{Ior, IorNel, NonEmptyList, ValidatedNel} +import cats.data.NonEmptyList trait ListSyntax { implicit def catsSyntaxList[A](la: List[A]): ListOps[A] = new ListOps(la) @@ -28,44 +27,4 @@ final class ListOps[A](val la: List[A]) extends AnyVal { * }}} */ def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) - - /** - * Returns a IorNel from a List - * - * Example: - * {{{ - * scala> import cats.data.IorNel - * scala> import cats.implicits._ - * - * scala> val result1: List[String] = List("error 1", "error 2") - * scala> result1.toIorNel(1) - * res0: IorNel[String, Int] = Left(NonEmptyList(error 1, error 2)) - * - * scala> val result2: List[String] = List.empty[String] - * scala> result2.toIorNel(1) - * res1: IorNel[String, Int] = Right(1) - * }}} - */ - def toIorNel[B](ifEmpty: => B): IorNel[A, B] = - toNel.fold[IorNel[A, B]](Ior.rightNel(ifEmpty))(Ior.left) - - /** - * Returns a ValidatedNel from a List - * - * Example: - * {{{ - * scala> import cats.data.ValidatedNel - * scala> import cats.implicits._ - * - * scala> val result1: List[String] = List("error 1", "error 2") - * scala> result1.toValidatedNel(1) - * res0: ValidatedNel[String, Int] = Invalid(NonEmptyList(error 1, error 2)) - * - * scala> val result2: List[String] = List.empty[String] - * scala> result2.toValidatedNel(1) - * res1: ValidatedNel[String, Int] = Valid(1) - * }}} - */ - def toValidatedNel[B](ifEmpty: => B): ValidatedNel[A, B] = - toNel.fold[ValidatedNel[A, B]](Valid(ifEmpty))(Invalid(_)) } diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 17b358e03a..0c85652904 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -204,12 +204,6 @@ class IorTests extends CatsSuite { } } - test("rightNel") { - forAll { (x: Int) => - Ior.rightNel(x).right should === (Some(x)) - } - } - test("leftNel") { forAll { (x: String) => Ior.leftNel(x).left should === (Some(NonEmptyList.of(x)))