当前位置: 首页>>代码示例>>Scala>>正文


Scala Validated类代码示例

本文整理汇总了Scala中cats.data.Validated的典型用法代码示例。如果您正苦于以下问题:Scala Validated类的具体用法?Scala Validated怎么用?Scala Validated使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。


在下文中一共展示了Validated类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Scala代码示例。

示例1: AssetProcessing

//设置package包名称以及导入依赖的类
package templates

import aws.Interpreter.ErrorsOr
import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, Validated, ValidatedNel}
import com.amazonaws.regions.{Region, Regions}
import com.ovoenergy.comms.model.{Channel, CommManifest}

object AssetProcessing {

  private val assetTemplateReferenceRegex = "(?:'|\")(?: *)(assets)(?:/[^(\"')]+)(?: *)(?:'|\")".r

  case class ProcessedFiles(templateFiles: List[UploadedTemplateFile], assetFiles: List[UploadedTemplateFile])

  def processAssets(region: Regions,
                    assetsS3Bucket: String,
                    commManifest: CommManifest,
                    uploadedFiles: List[UploadedTemplateFile]): ErrorsOr[ProcessedFiles] = {
    import cats.syntax.traverse._
    import cats.instances.list._
    val (assetFiles, nonAssetFiles) = uploadedFiles.partition(_.fileType == Asset)
    val processedTemplateFiles: Validated[NonEmptyList[String], List[UploadedTemplateFile]] = nonAssetFiles
      .traverseU(templateFile => {
        replaceAssetReferences(region, assetsS3Bucket, templateFile.channel, commManifest, templateFile.contents)
          .map(contents => templateFile.copy(contents = contents))
      })
    processedTemplateFiles.map(ProcessedFiles(_, assetFiles)).toEither
  }

  private def replaceAssetReferences(region: Regions,
                                     assetsS3Bucket: String,
                                     channel: Channel,
                                     commManifest: CommManifest,
                                     contents: Array[Byte]): ValidatedNel[String, Array[Byte]] = {
    def replaceReferences(s3Endpoint: String, contentsString: String) = {
      val replacementAssetsPath = s"$s3Endpoint/assets"
      assetTemplateReferenceRegex
        .replaceAllIn(contentsString, m => m.group(0).replaceFirst(m.group(1), replacementAssetsPath))
        .getBytes
    }
    determineS3Endpoint(region, assetsS3Bucket, channel, commManifest).map(replaceReferences(_, new String(contents)))
  }

  private def determineS3Endpoint(region: Regions,
                                  assetsS3Bucket: String,
                                  channel: Channel,
                                  commManifest: CommManifest): ValidatedNel[String, String] = {
    if (!Region.getRegion(region).isServiceSupported("s3")) {
      Invalid(NonEmptyList.of("S3 not supported in region selected"))
    } else if (!Region.getRegion(region).hasHttpsEndpoint("s3")) {
      Invalid(NonEmptyList.of("No https support for s3 in region selected"))
    } else {
      val s3ServiceEndpoint = Region.getRegion(region).getServiceEndpoint("s3")
      Valid(
        s"https://$s3ServiceEndpoint/$assetsS3Bucket/${commManifest.commType.toString.toLowerCase}/${commManifest.name}/${commManifest.version}/${channel.toString.toLowerCase}")
    }
  }
} 
开发者ID:ovotech,项目名称:comms-template-manager,代码行数:59,代码来源:AssetProcessing.scala

示例2: withReattempt

//设置package包名称以及导入依赖的类
package wiro

import io.circe._
import cats.data.Validated

//Shamelessy copied by circe, author is @travisbrown
trait CustomOptionDecoder {
  final def withReattempt[A](f: ACursor => Decoder.Result[A]): Decoder[A] = new Decoder[A] {
    final def apply(c: HCursor): Decoder.Result[A] = tryDecode(c)

    override def tryDecode(c: ACursor): Decoder.Result[A] = f(c)

    override def decodeAccumulating(c: HCursor): AccumulatingDecoder.Result[A] = tryDecodeAccumulating(c)

    override def tryDecodeAccumulating(c: ACursor): AccumulatingDecoder.Result[A] = f(c) match {
      case Right(v) => Validated.valid(v)
      case Left(e) => Validated.invalidNel(e)
    }
  }

  implicit final def decodeOption[A](implicit d: Decoder[A]): Decoder[Option[A]] = withReattempt {
    case c: HCursor =>
      if (c.value.isNull) rightNone else d(c) match {
        case Right(a) => Right(Some(a))
        //removed part of the code here
        case Left(df) => Left(df)
      }
    case c: FailedCursor =>
      if (!c.incorrectFocus) rightNone else Left(DecodingFailure("[A]Option[A]", c.history))
  }

  private[this] final val rightNone: Either[DecodingFailure, Option[Nothing]] = Right(None)
} 
开发者ID:buildo,项目名称:wiro,代码行数:34,代码来源:OptionDecoder.scala

示例3: beValid

//设置package包名称以及导入依赖的类
package tryp
package core

import cats.data.Validated

import org.specs2.matcher._

trait ValidatedMatchers
extends EitherMatchers
with MatchersImplicits
{
  def beValid[T](t: ValueCheck[T]) = ValidCheckedMatcher(t)
  def beValid[T] = ValidMatcher[T]()

  def beInvalid[T](t: ValueCheck[T]) = InvalidCheckedMatcher(t)
  def beInvalid[T] = InvalidMatcher[T]()
}

object ValidatedMatchers
extends ValidatedMatchers
{
  type V[A] = Validated[_, A]
  type I[A] = Validated[A, _]
}

import ValidatedMatchers._

case class ValidMatcher[T]()
extends OptionLikeMatcher[V, T, T]("Valid", _.toEither.right.toOption)

case class ValidCheckedMatcher[T](check: ValueCheck[T])
extends OptionLikeCheckedMatcher[V, T, T]( "Valid", _.toEither.right.toOption,
  check)

case class InvalidMatcher[T]()
extends OptionLikeMatcher[I, T, T]("Invalid", _.toEither.left.toOption)

case class InvalidCheckedMatcher[T](check: ValueCheck[T])
extends OptionLikeCheckedMatcher[I, T, T]("Invalid",
  _.toEither.left.toOption, check) 
开发者ID:tek,项目名称:pulsar,代码行数:41,代码来源:validated.scala

示例4: ValidatedTest

//设置package包名称以及导入依赖的类
package objektwerks.validated

import org.scalatest.{FunSuite, Matchers}

class ValidatedTest extends FunSuite with Matchers {
  test("instances") {
    import cats.data.Validated
    import cats.data.Validated.Valid
    import cats.data.Validated.Invalid

    Validated.Valid(3) shouldEqual Valid(3)
    Validated.Invalid("three") shouldEqual Invalid("three")
    Validated.valid[String, Int](3) shouldEqual Valid(3)
    Validated.invalid[String, Int]("three") shouldEqual Invalid("three")
  }

  test("syntax") {
    import cats.syntax.validated._
    import cats.data.Validated.Valid
    import cats.data.Validated.Invalid

    3.valid[String] shouldEqual Valid(3)
    "three".invalid[Int] shouldEqual Invalid("three")
  }

  test("methods") {
    import cats.data.Validated
    import cats.syntax.validated._
    import cats.data.Validated.Valid

    Validated.catchOnly[NumberFormatException]("three".toInt).isInvalid shouldBe true
    Validated.catchNonFatal(sys.error("Nonfatal")).isInvalid shouldBe true
    Validated.fromTry(scala.util.Try("three".toInt)).isInvalid shouldBe true
    Validated.fromEither[String, Int](Left("Error")).isInvalid shouldBe true
    Validated.fromOption[String, Int](None, "Error").isInvalid shouldBe true
    3.valid.map(_ * 3) shouldEqual Valid(9)
  }
} 
开发者ID:objektwerks,项目名称:typelevel,代码行数:39,代码来源:ValidatedTest.scala

示例5: ValidatedOps

//设置package包名称以及导入依赖的类
package freecli
package testkit

import cats.data.Validated
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.{FunSpec, Matchers}

trait Test extends FunSpec with Matchers with TypeCheckedTripleEquals {
  implicit class ValidatedOps[A, B](v: Validated[A, B]) {
    def invalid: A = v match {
      case [email protected](_) =>
        throw new IllegalArgumentException(
          s"Tried to access invalid but was valid $valid")

      case Validated.Invalid(a) => a
    }

    def valid: B = v match {
      case [email protected](_) =>
        throw new IllegalArgumentException(
          s"Tried to access valid but was invalid $invalid")

      case Validated.Valid(b) => b
    }
  }
} 
开发者ID:pavlosgi,项目名称:freecli,代码行数:27,代码来源:Test.scala

示例6: jsonDecodedStringDecoder

//设置package包名称以及导入依赖的类
package freecli
package circe

import scala.io.Source

import cats.Show
import cats.syntax.show._
import cats.data.{NonEmptyList, Validated, ValidatedNel}
import io.circe.{Decoder, Json}
import io.circe.parser.parse

import core.api.{StringDecoder, StringDecoderError}

trait Instances {
  implicit def jsonDecodedStringDecoder[T](
    implicit ev: StringDecoder[Json],
    show: Show[T],
    decoder: Decoder[T]):
    StringDecoder[T] = {

    new StringDecoder[T] {
      def apply(value: String): ValidatedNel[StringDecoderError, T] = {
        ev(value) match {
          case Validated.Valid(j) =>
            Validated.fromEither(j.as[T]).leftMap(
              f => NonEmptyList.of(StringDecoderError(f.message)))

          case Validated.Invalid(e) => Validated.Invalid(e)
        }
      }

      def toString(v: T): String = {
        v.show
      }
    }
  }

  implicit def jsonStringDecoder: StringDecoder[Json] = {
    new StringDecoder[Json] {
      def apply(value: String): ValidatedNel[StringDecoderError, Json] = {

        val stringToParse =
          if (value.matches(".+\\.json")) {
            Source.fromFile(value).mkString
          } else value

        parse(stringToParse) match {
          case Right(j) =>
            Validated.valid(j)

          case Left(e) => Validated.invalidNel(StringDecoderError(e.message))
        }
      }

      def toString(v: Json): String = {
        v.spaces2
      }
    }
  }
} 
开发者ID:pavlosgi,项目名称:freecli,代码行数:61,代码来源:Instances.scala

示例7: Decoder

//设置package包名称以及导入依赖的类
package freecli
package examples
package decoder

import cats.data.{Validated, ValidatedNel}

import freecli.argument.all._
import freecli.core.api.{StringDecoder, StringDecoderError}

object Decoder extends App {
  sealed trait Fruit
  case object Apple extends Fruit
  case object Pear extends Fruit
  case object Orange extends Fruit

  implicit object fruitStringDecoder extends StringDecoder[Fruit] {
    override def apply(value: String): ValidatedNel[StringDecoderError, Fruit] = {
      value match {
        case v if v.equalsIgnoreCase("Apple") => Validated.valid(Apple)
        case v if v.equalsIgnoreCase("Pear") => Validated.valid(Pear)
        case v if v.equalsIgnoreCase("Orange") => Validated.valid(Orange)
        case v =>
          Validated.invalidNel(StringDecoderError(
            s"$v did not match any of (Apple, Pear, Orange)"))
      }
    }

    override def toString(v: Fruit): String = {
      v match {
        case Apple => "Apple"
        case Pear => "Pear"
        case Orange => "Orange"
      }
    }
  }

  val res = runArgumentOrFail(arg[Fruit])(args)
  println(res)
} 
开发者ID:pavlosgi,项目名称:freecli,代码行数:40,代码来源:Decoder.scala

示例8: ProfileValidation

//设置package包名称以及导入依赖的类
package com.ovoenergy.orchestration.profile

import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, Validated}
import cats.{Apply, Semigroup}
import com.ovoenergy.comms.model.InvalidProfile
import com.ovoenergy.orchestration.domain.CustomerProfile
import com.ovoenergy.orchestration.logging.LoggingWithMDC
import com.ovoenergy.orchestration.processes.Orchestrator.ErrorDetails

object ProfileValidation extends LoggingWithMDC {

  case class ValidationError(message: String)
  case class ValidationErrors(errors: NonEmptyList[ValidationError]) {
    def errorsString: String = {
      errors.map(_.message).toList.mkString(", ")
    }
  }
  object ValidationErrors {
    def apply(message: String): ValidationErrors        = ValidationErrors(ValidationError(message))
    def apply(error: ValidationError): ValidationErrors = ValidationErrors(NonEmptyList.of(error))
    implicit val sg = new Semigroup[ValidationErrors] {
      def combine(x: ValidationErrors, y: ValidationErrors): ValidationErrors =
        ValidationErrors(x.errors.concat(y.errors))
    }
  }
  private type ValidationErrorsOr[A] = Validated[ValidationErrors, A]

  def apply(customerProfile: CustomerProfile): Either[ErrorDetails, CustomerProfile] = {
    val firstName: ValidationErrorsOr[String] = {
      if (customerProfile.name.firstName.isEmpty) Validated.invalid(ValidationErrors("Customer has no first name"))
      else Validated.valid(customerProfile.name.firstName)
    }

    val lastName: ValidationErrorsOr[String] = {
      if (customerProfile.name.lastName.isEmpty) Validated.invalid(ValidationErrors("Customer has no last name"))
      else Validated.valid(customerProfile.name.lastName)
    }

    val profileOrErrors = Apply[ValidationErrorsOr].map2(firstName, lastName) {
      case (validFirstName, validLastName) =>
        customerProfile
    }

    profileOrErrors match {
      case Valid(profile) => Right(profile)
      case Invalid(errors) =>
        Left(ErrorDetails(errors.errorsString, InvalidProfile))
    }
  }
} 
开发者ID:ovotech,项目名称:comms-orchestration,代码行数:52,代码来源:ProfileValidation.scala

示例9: printer

//设置package包名称以及导入依赖的类
package io.circe.spray

import cats.data.Validated
import io.circe.{ Errors, Printer, RootEncoder }
import io.circe.jawn._
import spray.http.{ ContentTypes, HttpCharsets, HttpEntity, MediaTypes }
import spray.httpx.marshalling.Marshaller
import spray.httpx.unmarshalling.Unmarshaller

trait JsonSupport {
  def printer: Printer

  implicit final def circeJsonMarshaller[A](implicit encoder: RootEncoder[A]): Marshaller[A] =
    Marshaller.delegate[A, String](ContentTypes.`application/json`) { value =>
      printer.pretty(encoder(value))
    }

  implicit def circeJsonUnmarshaller[A](implicit decoder: RootDecoder[A]): Unmarshaller[A]
}

trait FailFastUnmarshaller { this: JsonSupport =>
  implicit final def circeJsonUnmarshaller[A](implicit decoder: RootDecoder[A]): Unmarshaller[A] =
    Unmarshaller[A](MediaTypes.`application/json`) {
      case x: HttpEntity.NonEmpty =>
        decode[A](x.asString(defaultCharset = HttpCharsets.`UTF-8`))(decoder.underlying) match {
          case Right(a) => a
          case Left(e) => throw e
        }
    }
}

trait ErrorAccumulatingUnmarshaller { this: JsonSupport =>
  implicit final def circeJsonUnmarshaller[A](implicit decoder: RootDecoder[A]): Unmarshaller[A] =
    Unmarshaller[A](MediaTypes.`application/json`) {
      case x: HttpEntity.NonEmpty =>
        decodeAccumulating[A](x.asString(defaultCharset = HttpCharsets.`UTF-8`))(decoder.underlying) match {
          case Validated.Valid(result) => result
          case Validated.Invalid(errors) => throw Errors(errors)
        }
    }
}

trait NoSpacesPrinter { this: JsonSupport =>
  final def printer: Printer = Printer.noSpaces
}

final object JsonSupport extends JsonSupport with NoSpacesPrinter with FailFastUnmarshaller

final object ErrorAccumulatingJsonSupport extends JsonSupport with NoSpacesPrinter with ErrorAccumulatingUnmarshaller 
开发者ID:travisbrown,项目名称:circe-spray,代码行数:50,代码来源:JsonSupport.scala

示例10: CsvReader

//设置package包名称以及导入依赖的类
package ch.becompany.akka.io.csv

import akka.stream.scaladsl.{FlowOps, Source}
import cats.data.{NonEmptyList, Validated}
import cats.data.Validated.{invalid, valid}
import com.github.tototoshi.csv.{CSVParser, DefaultCSVFormat, QUOTE_MINIMAL, Quoting}

import scala.util.{Failure, Success, Try}

class CsvReader[T](spec: CsvSpec = CsvSpec())(implicit parser: LineParser[T]) {

  private val commentPattern = "^\\s*#".r

  private lazy val lineParser = new CSVParser(new DefaultCSVFormat() {
    override val delimiter: Char = spec.fieldDelimiter
    override val quoteChar: Char = spec.quote
    override val quoting: Quoting = QUOTE_MINIMAL
  })

  private def parseLine(line: String): LineResult[T] = {
    Try(lineParser.parseLine(line)) match {
      case Success(Some(fields)) => LineParser[T](fields.map(_.trim))
      case Success(None) => invalid(NonEmptyList(s"Invalid line: $line"))
      case Failure(e) => invalid(NonEmptyList(s"Invalid line: $line, ${e.getMessage}"))
    }
  }

  
  def read[Mat](source: Source[String, Mat]): Source[LineResult[T], Mat] =
    source.
      filterNot(commentPattern.findFirstIn(_).isDefined).
      map(parseLine)

} 
开发者ID:becompany,项目名称:akka-file-io,代码行数:35,代码来源:CsvReader.scala

示例11: FeedItem

//设置package包名称以及导入依赖的类
package com.eddsteel.feedfilter.model

import Errors._
import cats.implicits._
import cats.data.{Validated, ValidatedNel}
import java.net.URI
import scala.util.Try

final case class FeedItem(id: String, title: String, href: URI, description: String)

object FeedItem {
  import scala.xml._

  type Parsed = Either[FeedItemParseError, FeedItem]

  private def handleSax[A](unsafeCall: => A): Validated[FeedItemParseError, A] =
    Validated.fromTry(Try(unsafeCall)).leftMap(SaxProblem.apply)

  def handleAttr[A](unsafeCall: => A)(key: String): ValidatedNel[XmlMarshalProblem, A] =
    Validated
      .fromTry(Try(unsafeCall))
      .leftMap(_ => AttributeMarshalProblem(key, None))
      .toValidatedNel[XmlMarshalProblem, A]

  @SuppressWarnings(Array("org.wartremover.warts.Any", "org.wartremover.warts.Nothing"))
  def fromXML(s: String): Parsed = {
    val xml = handleSax(XML.loadString(s"<root>$s</root>")).toEither
    xml.flatMap { doc =>
      val validated = (handleAttr[String]((doc \ "guid").text)("guid") |@|
        handleAttr[String]((doc \ "title").text)("title") |@|
        handleAttr[String]((doc \ "link").text)("link").map(new URI(_)) |@|
        handleAttr[String]((doc \ "description").text)("description")).map(FeedItem.apply _)

      val end: Parsed = validated.leftMap(FeedItemMarshalError.apply).toEither
      end
    }
  }
} 
开发者ID:eddsteel,项目名称:feed-filter,代码行数:39,代码来源:FeedItem.scala

示例12: YamlFeedConfig

//设置package包名称以及导入依赖的类
package com.eddsteel.feedfilter.model.config

import com.eddsteel.feedfilter.model.Errors._
import cats.data.{Validated, ValidatedNel}
import cats.implicits._
import net.jcazevedo.moultingyaml._

import java.net.URI

final case class YamlFeedConfig(name: String, src: URI, extract: String, rule: Map[String, String]) {

  @SuppressWarnings(
    Array(
      "org.wartremover.warts.Any",
      "org.wartremover.warts.Nothing"
    ))
  def toFeedConfig: ValidatedNel[ConfigParseError, FeedConfig] = {
    val validatedRule: Validated[ConfigParseError, RuleConfig] = (for {
      ruleType <- rule.get("type").toRight(MissingFeedFilterRuleField("type"))
      ruleConfig <- RuleConfig.fromFields(ruleType, rule).toRight(UnknownFeedFilterRule(rule))
    } yield ruleConfig).toValidated

    (name.validNel[ConfigParseError]
      |@| src.validNel[ConfigParseError]
      |@| ExtractorChoice.fromString(extract).toValidNel(UnknownFeedItemExtractor(extract))
      |@| validatedRule.toValidatedNel).map(FeedConfig.apply _)
  }
}

object YamlFeedConfig extends DefaultYamlProtocol {
  implicit object UriYamlFormat extends YamlFormat[URI] {
    def write(u: URI) = YamlString(u.toString)
    def read(value: YamlValue) = value match {
      case YamlString(s) =>
        try { new URI(s) } catch {
          case _: Throwable => deserializationError(s"Expected valid URI, but got $s")
        }
      case y =>
        deserializationError(s"Expected Int as YamlNumber, but got $y")
    }
  }

  implicit val format: YamlFormat[YamlFeedConfig] = yamlFormat4(YamlFeedConfig.apply)

  def parse(yaml: String): Either[ConfigParseError, List[YamlFeedConfig]] =
    Either
      .catchOnly[DeserializationException](yaml.parseYaml.convertTo[List[YamlFeedConfig]])
      .left
      .map(t => YamlParseError(t))
} 
开发者ID:eddsteel,项目名称:feed-filter,代码行数:51,代码来源:YamlFeedConfig.scala

示例13: Predicate

//设置package包名称以及导入依赖的类
package rtb
package validation

import cats.data.{NonEmptyList,Validated,ValidatedNel}
import cats.std.list._
import cats.syntax.validated._
import cats.syntax.semigroup._

final case class Predicate[A](messages: NonEmptyList[String], check: A => Boolean) {
  def apply(a: A): ValidatedNel[String,A] =
    if(check(a))
      a.validNel
    else
      Validated.invalid(messages)

  def and(that: Predicate[A]): Predicate[A] =
    Predicate(this.messages |+| that.messages, (a: A) => this.check(a) && that.check(a))
}
object Predicate {
  def lift[A](message: String)(f: A => Boolean): Predicate[A] =
    Predicate(NonEmptyList(message), f)

  def lengthAtLeast(length: Int): Predicate[String] =
    Predicate.lift(s"Must be at least $length characters."){ string =>
      string.length >= length
    }

  val onlyLettersOrDigits: Predicate[String] =
    Predicate.lift("Must contain only letters or digits."){ string =>
      string.forall(_.isLetterOrDigit)
    }

  def containsAllChars(chars: String): Predicate[String] =
    Predicate.lift(s"Must contain all of $chars"){ string =>
      val chs = chars.toList
      chs.foldLeft(true){ (accum, elt) =>
        accum && string.contains(elt)
      }
    }
} 
开发者ID:underscoreio,项目名称:rtb,代码行数:41,代码来源:predicate.scala

示例14: Errors

//设置package包名称以及导入依赖的类
package com.ovoenergy.comms.composer

import cats.Semigroup
import cats.data.Validated
import com.ovoenergy.comms.model.ErrorCode

package object rendering {

  private[rendering] final case class Errors(missingKeys: Set[String],
                                             exceptions: Seq[Throwable],
                                             errorCode: ErrorCode) {
    def toErrorMessage: String = {
      val missingKeysMsg = {
        if (missingKeys.nonEmpty)
          s"""The template referenced the following non-existent keys:
             |${missingKeys.map(k => s" - $k").mkString("\n")}
           """.stripMargin
        else
          ""
      }
      val exceptionsMsg = {
        if (exceptions.nonEmpty)
          s"""The following exceptions were thrown:
             |${exceptions.map(e => s" - ${e.getMessage}").mkString("\n")}
           """.stripMargin
        else
          ""
      }
      s"$missingKeysMsg$exceptionsMsg"
    }
  }

  private[rendering] object Errors {
    implicit val semigroup: Semigroup[Errors] = new Semigroup[Errors] {
      override def combine(x: Errors, y: Errors): Errors =
        Errors(x.missingKeys ++ y.missingKeys, x.exceptions ++ y.exceptions, x.errorCode)
    }
  }

  private[rendering] type ErrorsOr[A] = Validated[Errors, A]

} 
开发者ID:ovotech,项目名称:comms-composer,代码行数:43,代码来源:package.scala

示例15: validateBooks

//设置package包名称以及导入依赖的类
package fp.validated

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.syntax.cartesian._
import cats.syntax.semigroup._
import cats.syntax.validated._
import fp.Genre.InvalidGenre
import fp.{Book, EmptyBookList, Error, Genre, InvalidParameter}

import scala.util.matching.Regex

trait BookValidationService {

  private val isbnRegex: Regex =
    """ISBN(?:-13)?:?\x20*(?=.{17}$)97(?:8|9)([ -])\d{1,5}\1\d{1,7}\1\d{1,6}\1\d$""".r

  def validateBooks(bs: List[Book]): Validated[NonEmptyList[Error], NonEmptyList[Book]] = bs match {
    case Nil => EmptyBookList("Book list was empty").invalidNel
    case books => books map validateBook reduce (_ |+| _)
  }

  def validateBook(b: Book): ValidatedNel[InvalidParameter, NonEmptyList[Book]] = (
    validateIsbn(b.isbn) |@|
    validateAuthor(b.author) |@|
    validateTitle(b.title) |@|
    validateGenre(b.genre) ) map {
    case (isbn, author, title, genre) =>
      NonEmptyList.of(Book(isbn, title, author, genre))
  }

  private def validateGenre(g: Genre): ValidatedNel[InvalidParameter, Genre] = g match {
    case InvalidGenre => InvalidParameter("Book has invalid genre").invalidNel
    case genre => genre.validNel
  }

  private def validateIsbn(isbn: String): ValidatedNel[InvalidParameter, String] = isbn match {
    case isbnRegex(all @ _*) => isbn.validNel
    case _ => InvalidParameter("isbn has not a valid format").invalidNel
  }

  private def validateTitle(title: String): ValidatedNel[InvalidParameter, String] =
    if (Option(title).exists(_.isEmpty)) InvalidParameter("title must not be empty").invalidNel else title.validNel

  private def validateAuthor(author: String): ValidatedNel[InvalidParameter, String] =
    if (Option(author).exists(_.isEmpty)) InvalidParameter("author must not be empty").invalidNel else author.validNel

} 
开发者ID:leandrob13,项目名称:fp-examples,代码行数:48,代码来源:BookValidationService.scala


注:本文中的cats.data.Validated类示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。