All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ammonite.util.Res.scala Maven / Gradle / Ivy

There is a newer version: 0.9.3
Show newest version
package ammonite.util

import acyclic.file
import scala.util.Try


/**
  * The result of a single pass through the ammonite REPL. Results in a single
  * [[T]], or of one of a fixed number of failures that are common for anyone
  * who is evaluating code via the REPL.
  */
sealed abstract class Res[+T]{
  def flatMap[V](f: T => Res[V]): Res[V]
  def map[V](f: T => V): Res[V]
  def filter(f: T => Boolean): Res[T] = this
}



object Res{
  /**
    * Maps a Res-returning function across a collection `M[T]`, failing fast and
    * bailing out if any individual element fails.
    */
  def map[M[_] <: Traversable[_], T, V](inputs: M[T])(f: T => Res[V])
                                       (implicit cbf: collection.generic.CanBuildFrom[_, V, M[V]])
  : Res[M[V]] = {
    val builder = cbf.apply()

    inputs.foldLeft[Res[Unit]](Res.Success()){
      case (f: Failing, _) => f
      case (Res.Success(prev), x: T) =>
        f(x) match{
          case f: Failing => f
          case Success(x) =>
            builder += x
            Res.Success(())
        }
    } match{
      case Success(_) => Res.Success(builder.result())
      case f: Failing => f
    }
  }
  def apply[T](o: Option[T], errMsg: => String) = o match{
    case Some(s) => Success(s)
    case None => Failure(None, errMsg)
  }
  def apply[T](o: Try[T], errMsg: Throwable => String) = o match{
    case util.Success(s) => Success(s)
    case util.Failure(t) => Failure(None, errMsg(t))
  }

  /**
    * Successes map and flatmap just like a simple Box[T]
    */
  case class Success[+T](s: T) extends Res[T] {
    def flatMap[V](f: T => Res[V]): Res[V] = f(s) match {
      case Success(v) => Success(v)
      case other => other
    }

    def map[V](f: T => V): Res[V] = Success(f(s))
  }

  /**
    * Failing results never call their callbacks, and just remain unchanged
    */
  sealed abstract class Failing extends Res[Nothing]{
    def flatMap[V](f: Nothing => Res[V]): Res[V] = this
    def map[V](f: Nothing => V): Res[V] = this
  }

  /**
    * A known failure occured, maybe caused by an exception
    * (e.g. `ThreadDeath`) and maybe not (e.g. compile error)
    *
    * @param ex is any exception that caused this known failure; currently
    *           only used for the "Interrupted!" failures caused by Ctrl-C
    * @param msg the message we want to display on screen due to this failure
    */
  case class Failure(ex: Option[Throwable], msg: String) extends Failing

  /**
    * An unknown exception was thrown when the command was being run
    */
  case class Exception(t: Throwable, s: String) extends Failing

  /**
    * Nothing was entered
    */
  case object Skip extends Failing

  /**
    * The user wanted to exit the REPL
    */
  case class Exit(value: Any) extends Failing
}


/**
  * Fake for-comprehension generator to catch errors and turn
  * them into [[Res.Failure]]s
  */
case class Catching(handler: PartialFunction[Throwable, Res.Failing]) {

  def foreach[T](t: Unit => T): T = t(())
  def flatMap[T](t: Unit => Res[T]): Res[T] =
    try{t(())} catch handler
  def map[T](t: Unit => T): Res[T] =
    try Res.Success(t(())) catch handler
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy