Skip to content

Commit

Permalink
Merge pull request #135 from geirolz/add-decoder-or-method
Browse files Browse the repository at this point in the history
Add decoder Or method
  • Loading branch information
geirolz authored Sep 21, 2023
2 parents 064b74d + 13a3e40 commit c30c83c
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
29 changes: 11 additions & 18 deletions core/src/main/scala/cats/xml/codec/Decoder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ trait Decoder[T] {

def flatMap[U](f: T => Decoder[U]): Decoder[U] =
Decoder.of(ns => decodeCursorResult(ns).andThen(t => f(t).decodeCursorResult(ns)))

def or(other: Decoder[? <: T]): Decoder[T] =
this.attempt.flatMap {
case Left(_) => other.widen[T]
case Right(t) => Decoder.pure(t)
}
}

object Decoder extends DecoderInstances with DecoderSyntax {
Expand All @@ -66,27 +72,14 @@ object Decoder extends DecoderInstances with DecoderSyntax {
def const[T](r: => Decoder.Result[T]): Decoder[T] =
Decoder.of(_ => r)

def oneOf[T <: Any](
def oneOf[T](
d: Decoder[? <: T],
d1: Decoder[? <: T],
dn: Decoder[? <: T]*
): Decoder[? <: T] =
Decoder.instance(xml => {
NonEmptyList
.of(d, (d1 +: dn)*)
.foldLeft[Decoder.Result[T]](
DecoderFailure.Custom("Cannot decode the value.").invalidNel[T]
)((err, decoder) => {
err match {
case v @ Validated.Valid(_) => v
case Validated.Invalid(errors1) =>
decoder.decode(xml) match {
case v @ Validated.Valid(_) => v
case Validated.Invalid(errors2) => errors2.concatNel(errors1).invalid[T]
}
}
})
})
): Decoder[T] =
(List(d, d1) ++ dn.toList)
.map(_.widen[T])
.reduceLeft(_ or _)

def fromCursor[U](
f: NodeCursor => FreeCursor[Xml, U]
Expand Down
22 changes: 22 additions & 0 deletions core/src/test/scala/cats/xml/codec/decoderSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,28 @@ class DecoderSuite extends munit.FunSuite {
expected = DecoderFailure.Custom("ERROR 1").invalidNel
)
}

test("Decoder.or - fail or success") {

val decoderStr1: Decoder[String] = Decoder.failure(DecoderFailure.Custom("ERROR"))
val decoderStr2: Decoder[String] = Decoder.decodeString

assertEquals(
obtained = decoderStr1.or(decoderStr2).decode(Xml.ofString("test")),
expected = Valid("test")
)
}

test("Decoder.or - success or fail") {

val decoderStr1: Decoder[String] = Decoder.decodeString
val decoderStr2: Decoder[String] = Decoder.failure(DecoderFailure.Custom("ERROR"))

assertEquals(
obtained = decoderStr1.or(decoderStr2).decode(Xml.ofString("test")),
expected = Valid("test")
)
}
}

class DecoderInstancesSuite extends munit.DisciplineSuite {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats.xml.testing

import org.scalacheck.{Arbitrary, Gen}

case class VeryLongNumericString private (str: String) extends AnyVal
case class VeryLongNumericString(str: String) extends AnyVal
object VeryLongNumericString {

private[VeryLongNumericString] def apply(str: String): VeryLongNumericString =
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/scala/cats/xml/testing/XmlValidName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package cats.xml.testing
import cats.xml.Xml
import org.scalacheck.{Arbitrary, Gen}

case class XmlValidName private (value: String) extends AnyVal
case class XmlValidName(value: String) extends AnyVal
object XmlValidName {

private def apply(value: String): XmlValidName =
Expand Down

0 comments on commit c30c83c

Please sign in to comment.