Skip to content

Commit

Permalink
Merge pull request #88 from stevenheidel/moremethods
Browse files Browse the repository at this point in the history
Add a couple inferred methods and aliases to clump api
  • Loading branch information
fwbrasil committed Apr 24, 2015
2 parents 480c7bf + 8215558 commit d0799f9
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 1 deletion.
40 changes: 40 additions & 0 deletions src/main/scala/io/getclump/Clump.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,31 @@ sealed trait Clump[+T] {
*/
def handle[B >: T](f: PartialFunction[Throwable, Option[B]]): Clump[B] = new ClumpHandle(this, f)

/**
* Alias for [[handle]]
*/
def recover[B >: T](f: PartialFunction[Throwable, Option[B]]): Clump[B] = handle(f)

/**
* Define a fallback clump to use in the case of specified exceptions
*/
def rescue[B >: T](f: PartialFunction[Throwable, Clump[B]]): Clump[B] = new ClumpRescue(this, f)

/**
* Alias for [[rescue]]
*/
def recoverWith[B >: T](f: PartialFunction[Throwable, Clump[B]]): Clump[B] = rescue(f)

/**
* On any exception, fallback to a default value
*/
def fallback[B >: T](default: => Option[B]): Clump[B] = handle(PartialFunction(_ => default))

/**
* On any exception, fallback to a default clump
*/
def fallbackTo[B >: T](default: => Clump[B]): Clump[B] = rescue(PartialFunction(_ => default))

/**
* Alias for [[filter]] used by for-comprehensions
*/
Expand All @@ -46,6 +66,11 @@ sealed trait Clump[+T] {
*/
def filter[B >: T](f: B => Boolean): Clump[B] = new ClumpFilter(this, f)

/**
* If this clump does not return a value then use the default instead
*/
def orElse[B >: T: ClassTag](default: => B): Clump[B] = new ClumpOrElse(this, Clump.value(default))

/**
* If this clump does not return a value then use the value from a default clump instead
*/
Expand Down Expand Up @@ -96,6 +121,11 @@ object Clump extends Joins with Sources {
*/
def empty[T]: Clump[T] = value(scala.None)

/**
* Alias for [[value]] except that it propagates exceptions inside a clump instance
*/
def apply[T](value: => T): Clump[T] = try { this.value(value) } catch { case e: Throwable => this.exception(e) }

/**
* The unit method: create a clump whose value has already been resolved to the input
*/
Expand All @@ -106,11 +136,21 @@ object Clump extends Joins with Sources {
*/
def value[T](value: Option[T]): Clump[T] = future(Future.value(value))

/**
* Alias for [[value]]
*/
def successful[T](value: T): Clump[T] = this.value(value)

/**
* Create a failed clump with the given exception
*/
def exception[T](exception: Throwable): Clump[T] = future(Future.exception(exception))

/**
* Alias for [[exception]]
*/
def failed[T](exception: Throwable): Clump[T] = this.exception(exception)

/**
* Create a clump whose value will be the result of the inputted future
*/
Expand Down
1 change: 0 additions & 1 deletion src/main/scala/io/getclump/ClumpSource.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.getclump

import com.twitter.util.Future
import scala.collection.generic.CanBuildFrom

class ClumpSource[T, U] private[getclump] (val functionIdentity: FunctionIdentity,
val fetch: Set[T] => Future[Map[T, U]],
Expand Down
100 changes: 100 additions & 0 deletions src/test/scala/io/getclump/ClumpApiSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,25 @@ class ClumpApiSpec extends Spec {
}
}

"from a value (Clump.apply)" >> {
"propogates exceptions" in {
val clump = Clump { throw new IllegalStateException }
clumpResult(clump) must throwA[IllegalStateException]
}

"no exception" in {
clumpResult(Clump(1)) mustEqual Some(1)
}
}

"from a value (Clump.value)" in {
clumpResult(Clump.value(1)) mustEqual Some(1)
}

"from a value (Clump.successful)" in {
clumpResult(Clump.successful(1)) mustEqual Some(1)
}

"from an option (Clump.value)" >> {

"defined" in {
Expand All @@ -51,6 +66,10 @@ class ClumpApiSpec extends Spec {
"failed (Clump.exception)" in {
clumpResult(Clump.exception(new IllegalStateException)) must throwA[IllegalStateException]
}

"failed (Clump.failed)" in {
clumpResult(Clump.failed(new IllegalStateException)) must throwA[IllegalStateException]
}
}

"allows to create a clump traversing multiple inputs (Clump.traverse)" in {
Expand Down Expand Up @@ -186,6 +205,30 @@ class ClumpApiSpec extends Spec {
}
}

"using a function that recovers using a new value (clump.recover)" >> {
"exception happens" in {
val clump =
Clump.exception(new IllegalStateException).recover {
case e: IllegalStateException => Some(2)
}
clumpResult(clump) mustEqual Some(2)
}
"exception doesn't happen" in {
val clump =
Clump.value(1).recover {
case e: IllegalStateException => None
}
clumpResult(clump) mustEqual Some(1)
}
"exception isn't caught" in {
val clump =
Clump.exception(new NullPointerException).recover {
case e: IllegalStateException => Some(1)
}
clumpResult(clump) must throwA[NullPointerException]
}
}

"using a function that recovers the failure using a new clump (clump.rescue)" >> {
"exception happens" in {
val clump =
Expand All @@ -209,6 +252,54 @@ class ClumpApiSpec extends Spec {
clumpResult(clump) must throwA[NullPointerException]
}
}

"using a function that recovers the failure using a new clump (clump.recoverWith)" >> {
"exception happens" in {
val clump =
Clump.exception(new IllegalStateException).recoverWith {
case e: IllegalStateException => Clump.value(2)
}
clumpResult(clump) mustEqual Some(2)
}
"exception doesn't happen" in {
val clump =
Clump.value(1).recoverWith {
case e: IllegalStateException => Clump.value(None)
}
clumpResult(clump) mustEqual Some(1)
}
"exception isn't caught" in {
val clump =
Clump.exception(new NullPointerException).recoverWith {
case e: IllegalStateException => Clump.value(1)
}
clumpResult(clump) must throwA[NullPointerException]
}
}

"using a function that recovers using a new value (clump.fallback) on any exception" >> {
"exception happens" in {
val clump = Clump.exception(new IllegalStateException).fallback(Some(1))
clumpResult(clump) mustEqual Some(1)
}

"exception doesn't happen" in {
val clump = Clump.value(1).fallback(Some(2))
clumpResult(clump) mustEqual Some(1)
}
}

"using a function that recovers using a new clump (clump.fallbackTo) on any exception" >> {
"exception happens" in {
val clump = Clump.exception(new IllegalStateException).fallbackTo(Clump.value(1))
clumpResult(clump) mustEqual Some(1)
}

"exception doesn't happen" in {
val clump = Clump.value(1).fallbackTo(Clump.value(2))
clumpResult(clump) mustEqual Some(1)
}
}
}

"can have its result filtered (clump.filter)" in {
Expand All @@ -225,6 +316,15 @@ class ClumpApiSpec extends Spec {
}

"allows to defined a fallback value (clump.orElse)" >> {
"undefined" in {
clumpResult(Clump.empty.orElse(1)) ==== Some(1)
}
"defined" in {
clumpResult(Clump.value(Some(1)).orElse(2)) ==== Some(1)
}
}

"allows to defined a fallback clump (clump.orElse)" >> {
"undefined" in {
clumpResult(Clump.empty.orElse(Clump.value(1))) ==== Some(1)
}
Expand Down

0 comments on commit d0799f9

Please sign in to comment.