From 8bda070b437d3fc1e8387eee5562e06b59d99562 Mon Sep 17 00:00:00 2001 From: geirolz Date: Tue, 17 Oct 2023 13:46:06 +0200 Subject: [PATCH] Drop I type parameter for FreeCursor --- .../main/scala/cats/xml/codec/Decoder.scala | 4 +- .../main/scala/cats/xml/cursor/Cursor.scala | 2 +- .../scala/cats/xml/cursor/FreeCursor.scala | 66 ++++++++----------- core/src/main/scala/cats/xml/xmlNode.scala | 2 +- .../cats/xml/cursor/FreeCursorSuite.scala | 18 ++--- docs/compiled/README.md | 4 +- docs/source/README.md | 4 +- .../cats/xml/generic/MagnoliaDecoder.scala | 8 +-- .../cats/xml/generic/MagnoliaDecoder.scala | 4 +- 9 files changed, 51 insertions(+), 61 deletions(-) diff --git a/core/src/main/scala/cats/xml/codec/Decoder.scala b/core/src/main/scala/cats/xml/codec/Decoder.scala index 763374a..2aac289 100644 --- a/core/src/main/scala/cats/xml/codec/Decoder.scala +++ b/core/src/main/scala/cats/xml/codec/Decoder.scala @@ -5,7 +5,7 @@ import cats.data.* import cats.xml.* import cats.xml.cursor.{Cursor, FreeCursor, NodeCursor} import cats.xml.cursor.NodeCursor.Root -import cats.xml.XmlData.{XmlNumber, *} +import cats.xml.XmlData.* import scala.collection.Factory import scala.reflect.ClassTag @@ -82,7 +82,7 @@ object Decoder extends DecoderInstances with DecoderSyntax { .reduceLeft(_ or _) def fromCursor[U]( - f: NodeCursor => FreeCursor[Xml, U] + f: NodeCursor => FreeCursor[U] ): Decoder[U] = Decoder.of { case Left(failure) => DecoderFailure.CursorFailed(failure).invalidNel case Right(xml: Xml) => diff --git a/core/src/main/scala/cats/xml/cursor/Cursor.scala b/core/src/main/scala/cats/xml/cursor/Cursor.scala index bdba90f..3659e43 100644 --- a/core/src/main/scala/cats/xml/cursor/Cursor.scala +++ b/core/src/main/scala/cats/xml/cursor/Cursor.scala @@ -34,7 +34,7 @@ sealed trait Cursor[+X <: Xml] extends Serializable { * @return * A new `FreeCursor` */ - def as[T: Decoder]: FreeCursor[Xml, T] = + def as[T: Decoder]: FreeCursor[T] = FreeCursor[T](this) /** A String representation of the cursor. diff --git a/core/src/main/scala/cats/xml/cursor/FreeCursor.scala b/core/src/main/scala/cats/xml/cursor/FreeCursor.scala index e43bf39..7035840 100644 --- a/core/src/main/scala/cats/xml/cursor/FreeCursor.scala +++ b/core/src/main/scala/cats/xml/cursor/FreeCursor.scala @@ -7,15 +7,12 @@ import cats.xml.{Xml, XmlNode} import cats.xml.codec.{Decoder, DecoderFailure} import cats.xml.validator.Validator -/** `FreeCursor` represent a cursor with a free `O` type as result of the focusing and a free `I` - * type as target of the focusing. +/** `FreeCursor` represent a cursor with a free `O` type as result of the focusing. * - * @tparam I - * Input type of the `FreeCursor` * @tparam O * Output type of the `FreeCursor` */ -sealed trait FreeCursor[I, +O] extends Serializable { $this => +sealed trait FreeCursor[+O] extends Serializable { $this => /** Apply the current cursor to the specified input of type `I`. This allows to select a precise * part of the input `I` tree. @@ -27,7 +24,7 @@ sealed trait FreeCursor[I, +O] extends Serializable { $this => * @return * `Right` when succeed `Left` when fail */ - def focus(input: I): FreeCursor.Result[O] + def focus(input: Xml): FreeCursor.Result[O] /** Map the result of this cursor when succeed * @param f @@ -38,7 +35,7 @@ sealed trait FreeCursor[I, +O] extends Serializable { $this => * A new `FreeCursor` which once applied, apply this cursor and then if succeed apply the * function `f` in order to map the result */ - def map[U](f: O => U): FreeCursor[I, U] = + def map[U](f: O => U): FreeCursor[U] = FreeCursor.of($this.focus(_).map(f)) /** Create a new `FreeCursor` where the output of this cursor is validated with the specified @@ -50,8 +47,8 @@ sealed trait FreeCursor[I, +O] extends Serializable { $this => * @return * A new validated `FreeCursor` */ - def validate[OO >: O](validator: Validator[OO]): FreeCursor[I, OO] = - FreeCursor.of((input: I) => + def validate[OO >: O](validator: Validator[OO]): FreeCursor[OO] = + FreeCursor.of((input: Xml) => $this.focus(input).andThen(o => validator(o) .leftMap(eNel => NonEmptyList.one(CursorFailure.ValidationsFailed("** UNKNOWN **", eNel))) @@ -64,27 +61,24 @@ object FreeCursor extends FreeCursorInstances { type Result[+T] = ValidatedNel[CursorFailure, T] - def id[T]: FreeCursor[T, T] = - FreeCursor.of(_.validNel) - - def pure[I, O](value: O): FreeCursor[I, O] = + def pure[O](value: O): FreeCursor[O] = const(value.validNel) - def failure[I, O](value: NonEmptyList[CursorFailure]): FreeCursor[I, O] = + def failure[O](value: NonEmptyList[CursorFailure]): FreeCursor[O] = const(value.invalid) - def const[I, O](result: FreeCursor.Result[O]): FreeCursor[I, O] = + def const[O](result: FreeCursor.Result[O]): FreeCursor[O] = FreeCursor.of(_ => result) - private[xml] def of[I, O](f: I => FreeCursor.Result[O]): FreeCursor[I, O] = - new FreeCursor[I, O] { - override def focus(input: I): Result[O] = f(input) + private[xml] def of[O](f: Xml => FreeCursor.Result[O]): FreeCursor[O] = + new FreeCursor[O] { + override def focus(input: Xml): Result[O] = f(input) } def apply[O: Decoder]( cursor: Cursor[Xml] - ): FreeCursor[Xml, O] = - new FreeCursor[Xml, O] { $this => + ): FreeCursor[O] = + new FreeCursor[O] { $this => override def focus(xml: Xml): FreeCursor.Result[O] = { val cursorResult: Cursor.Result[Xml] = xml match { @@ -123,7 +117,7 @@ object FreeCursor extends FreeCursorInstances { } } - override def validate[OO >: O](validator: Validator[OO]): FreeCursor[Xml, OO] = + override def validate[OO >: O](validator: Validator[OO]): FreeCursor[OO] = FreeCursor.of((input: Xml) => $this.focus(input).andThen(o => validator(o) @@ -135,38 +129,30 @@ object FreeCursor extends FreeCursorInstances { private[xml] trait FreeCursorInstances { - implicit def applicativeErrorForFreeCursor[I] - : ApplicativeError[FreeCursor[I, *], NonEmptyList[CursorFailure]] = - new ApplicativeError[FreeCursor[I, *], NonEmptyList[CursorFailure]] { + implicit val applicativeErrorForFreeCursor + : ApplicativeError[FreeCursor, NonEmptyList[CursorFailure]] = + new ApplicativeError[FreeCursor, NonEmptyList[CursorFailure]] { - override def map[A, B](fa: FreeCursor[I, A])(f: A => B): FreeCursor[I, B] = + override def map[A, B](fa: FreeCursor[A])(f: A => B): FreeCursor[B] = fa.map(f) - def pure[A](a: A): FreeCursor[I, A] = + def pure[A](a: A): FreeCursor[A] = FreeCursor.pure(a) - def ap[A, B](ff: FreeCursor[I, A => B])(fa: FreeCursor[I, A]): FreeCursor[I, B] = - FreeCursor.of((input: I) => fa.focus(input).ap(ff.focus(input))) - - override def product[A, B]( - fa: FreeCursor[I, A], - fb: FreeCursor[I, B] - ): FreeCursor[I, (A, B)] = - FreeCursor.of((input: I) => fa.focus(input).product(fb.focus(input))) - - override def unit: FreeCursor[I, Unit] = pure(()) + def ap[A, B](ff: FreeCursor[A => B])(fa: FreeCursor[A]): FreeCursor[B] = + FreeCursor.of((input: Xml) => fa.focus(input).ap(ff.focus(input))) def handleErrorWith[A]( - fa: FreeCursor[I, A] - )(f: NonEmptyList[CursorFailure] => FreeCursor[I, A]): FreeCursor[I, A] = - FreeCursor.of((input: I) => + fa: FreeCursor[A] + )(f: NonEmptyList[CursorFailure] => FreeCursor[A]): FreeCursor[A] = + FreeCursor.of((input: Xml) => fa.focus(input) match { case Validated.Invalid(e) => f(e).focus(input) case v @ Validated.Valid(_) => v } ) - def raiseError[A](e: NonEmptyList[CursorFailure]): FreeCursor[I, A] = + def raiseError[A](e: NonEmptyList[CursorFailure]): FreeCursor[A] = FreeCursor.const(Validated.Invalid(e)) } } diff --git a/core/src/main/scala/cats/xml/xmlNode.scala b/core/src/main/scala/cats/xml/xmlNode.scala index b93291c..4eac46e 100644 --- a/core/src/main/scala/cats/xml/xmlNode.scala +++ b/core/src/main/scala/cats/xml/xmlNode.scala @@ -671,7 +671,7 @@ sealed trait XmlNodeSyntax { * @return * Cursor result, Left when fails Right when succeed */ - def focus[T](f: NodeCursor.Root.type => FreeCursor[Xml, T]): FreeCursor.Result[T] = + def focus[T](f: NodeCursor.Root.type => FreeCursor[T]): FreeCursor.Result[T] = f(Root).focus(node) def modify(f: NodeCursor.Root.type => Modifier[XmlNode]): Modifier.Result[XmlNode] = diff --git a/core/src/test/scala/cats/xml/cursor/FreeCursorSuite.scala b/core/src/test/scala/cats/xml/cursor/FreeCursorSuite.scala index 8f11b49..39b3e29 100644 --- a/core/src/test/scala/cats/xml/cursor/FreeCursorSuite.scala +++ b/core/src/test/scala/cats/xml/cursor/FreeCursorSuite.scala @@ -2,7 +2,7 @@ package cats.xml.cursor import cats.data.NonEmptyList import cats.data.Validated.{Invalid, Valid} -import cats.xml.{Xml, XmlNode} +import cats.xml.XmlNode import cats.xml.cursor.NodeCursor.Root import cats.xml.validator.Validator @@ -10,7 +10,7 @@ class FreeCursorSuite extends munit.FunSuite { test("FreeCursor.focus - valid") { - val cursor: FreeCursor[Xml, Int] = Root.bar.test.as[Int] + val cursor: FreeCursor[Int] = Root.bar.test.as[Int] val node: XmlNode = XmlNode("foo") .withChildren( @@ -28,8 +28,8 @@ class FreeCursorSuite extends munit.FunSuite { test("FreeCursor.focus - invalid") { - val cursor: FreeCursor[Xml, Int] = Root.bar.test.as[Int] - val incompleteNode: XmlNode = XmlNode("foo").withChildren(XmlNode("bar")) + val cursor: FreeCursor[Int] = Root.bar.test.as[Int] + val incompleteNode: XmlNode = XmlNode("foo").withChildren(XmlNode("bar")) assertEquals( obtained = cursor.focus(incompleteNode), @@ -39,7 +39,7 @@ class FreeCursorSuite extends munit.FunSuite { test("FreeCursor.map") { - val cursor: FreeCursor[Xml, Int] = Root.bar.test.as[Int] + val cursor: FreeCursor[Int] = Root.bar.test.as[Int] val node: XmlNode = XmlNode("foo") .withChildren( @@ -57,7 +57,7 @@ class FreeCursorSuite extends munit.FunSuite { test("FreeCursor.validate - valid") { - val cursor: FreeCursor[Xml, Int] = Root.bar.test.as[Int] + val cursor: FreeCursor[Int] = Root.bar.test.as[Int] val node: XmlNode = XmlNode("foo") .withChildren( @@ -77,7 +77,7 @@ class FreeCursorSuite extends munit.FunSuite { test("FreeCursor.validate - invalid") { - val cursor: FreeCursor[Xml, Int] = Root.bar.test.as[Int] + val cursor: FreeCursor[Int] = Root.bar.test.as[Int] val node: XmlNode = XmlNode("foo") .withChildren( @@ -112,11 +112,11 @@ class FreeCursorSuite extends munit.FunSuite { // import cats.laws.discipline.arbitrary.* // import cats.xml.testing.codec.arbitrary.* // -// implicit def eqFreeCursor[I, O]: Eq[FreeCursor[I, O]] = Eq.allEqual +// implicit def eqFreeCursor[O]: Eq[FreeCursor[O]] = Eq.allEqual // // checkAll( // "FreeCursor.ApplicativeErrorTests", -// ApplicativeErrorTests[FreeCursor[XmlNode, *], NonEmptyList[CursorFailure]] +// ApplicativeErrorTests[FreeCursor, NonEmptyList[CursorFailure]] // .applicativeError[Int, Int, String] // ) //} diff --git a/docs/compiled/README.md b/docs/compiled/README.md index 1e59090..152a8f6 100644 --- a/docs/compiled/README.md +++ b/docs/compiled/README.md @@ -116,13 +116,15 @@ val encoder: Encoder[Foo] = Encoder.of(t => ``` ### Navigating + ```scala import cats.xml.XmlNode import cats.xml.cursor.Cursor import cats.xml.cursor.FreeCursor import cats.xml.implicits.* -val node = xml""" +val node = + xml""" 1 diff --git a/docs/source/README.md b/docs/source/README.md index f10c7c1..dd52c38 100644 --- a/docs/source/README.md +++ b/docs/source/README.md @@ -107,13 +107,15 @@ val encoder: Encoder[Foo] = Encoder.of(t => ``` ### Navigating + ```scala mdoc:reset import cats.xml.XmlNode import cats.xml.cursor.Cursor import cats.xml.cursor.FreeCursor import cats.xml.implicits.* -val node = xml""" +val node = + xml""" 1 diff --git a/modules/generic/src/main/scala-2/cats/xml/generic/MagnoliaDecoder.scala b/modules/generic/src/main/scala-2/cats/xml/generic/MagnoliaDecoder.scala index 06d4f73..8086a34 100644 --- a/modules/generic/src/main/scala-2/cats/xml/generic/MagnoliaDecoder.scala +++ b/modules/generic/src/main/scala-2/cats/xml/generic/MagnoliaDecoder.scala @@ -1,9 +1,9 @@ package cats.xml.generic import cats.data.NonEmptyList +import cats.xml.XmlNode import cats.xml.codec.{Decoder, DecoderFailure} import cats.xml.cursor.{CursorFailure, FreeCursor} -import cats.xml.{Xml, XmlNode} import cats.xml.utils.generic.ParamName import magnolia1.{CaseClass, Param, SealedTrait, Subtype} @@ -34,7 +34,7 @@ object MagnoliaDecoder { val normalizedLabel: String = paramInfo.labelMapper(param.label) // find and decoder element - val result: Option[FreeCursor[Xml, param.PType]] = paramInfo.elemType match { + val result: Option[FreeCursor[param.PType]] = paramInfo.elemType match { case XmlElemType.Attribute => Some(c.attr(normalizedLabel).as[param.PType]) case XmlElemType.Child => Some(c.down(normalizedLabel).as[param.PType]) case XmlElemType.Text => Some(c.text.as[param.PType]) @@ -90,11 +90,11 @@ object MagnoliaDecoder { // Internal error: unable to find the outer accessor symbol of class $read private def useDefaultParameterIfPresentToRecoverMissing[F[_], T, PT]( param: Param[F, T] - ): PartialFunction[NonEmptyList[CursorFailure], FreeCursor[Xml, PT]] = { failures => + ): PartialFunction[NonEmptyList[CursorFailure], FreeCursor[PT]] = { failures => if (failures.forall(_.isMissing)) param.default match { case Some(value) => - FreeCursor.const[Xml, PT](value.asInstanceOf[PT].validNel[CursorFailure]) + FreeCursor.const[PT](value.asInstanceOf[PT].validNel[CursorFailure]) case None => FreeCursor.failure(failures) } else diff --git a/modules/generic/src/main/scala-3/cats/xml/generic/MagnoliaDecoder.scala b/modules/generic/src/main/scala-3/cats/xml/generic/MagnoliaDecoder.scala index 0dbad82..231349c 100644 --- a/modules/generic/src/main/scala-3/cats/xml/generic/MagnoliaDecoder.scala +++ b/modules/generic/src/main/scala-3/cats/xml/generic/MagnoliaDecoder.scala @@ -37,7 +37,7 @@ // val normalizedLabel: String = paramInfo.labelMapper(param.label) // // // find and decoder element -// val result: Option[FreeCursor[Xml, param.PType]] = paramInfo.elemType match { +// val result: Option[FreeCursor[param.PType]] = paramInfo.elemType match { // case XmlElemType.Attribute => Some(c.attr(normalizedLabel).as[param.PType]) // case XmlElemType.Child => Some(c.down(normalizedLabel).as[param.PType]) // case XmlElemType.Text => Some(c.text.as[param.PType]) @@ -82,7 +82,7 @@ // // Internal error: unable to find the outer accessor symbol of class $read // private def useDefaultParameterIfPresentToRecoverMissing[F[_], T, PT]( // param: Param[F, T] -// ): PartialFunction[NonEmptyList[CursorFailure], FreeCursor[Xml, PT]] = { failures => +// ): PartialFunction[NonEmptyList[CursorFailure], FreeCursor[PT]] = { failures => // if (failures.forall(_.isMissing)) // param.default match { // case Some(value) =>