Skip to content

Commit

Permalink
Validated.catchOnly and catchAll
Browse files Browse the repository at this point in the history
  • Loading branch information
ceedubs committed Nov 4, 2015
1 parent c5069eb commit 5411e93
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 17 deletions.
16 changes: 11 additions & 5 deletions core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -228,22 +228,28 @@ trait ValidatedFunctions {
* the resulting `Validated`. Uncaught exceptions are propagated.
*
* For example: {{{
* val result: Validated[NumberFormatException, Int] = fromTryCatch[NumberFormatException] { "foo".toInt }
* val result: Validated[NumberFormatException, Int] = catchOnly[NumberFormatException] { "foo".toInt }
* }}}
*/
def fromTryCatch[T >: Null <: Throwable]: FromTryCatchPartiallyApplied[T] = new FromTryCatchPartiallyApplied[T]
def catchOnly[T >: Null <: Throwable]: CatchOnlyPartiallyApplied[T] = new CatchOnlyPartiallyApplied[T]

final class FromTryCatchPartiallyApplied[T] private[ValidatedFunctions] {
def apply[A](f: => A)(implicit T: ClassTag[T]): Validated[T, A] = {
final class CatchOnlyPartiallyApplied[T] private[ValidatedFunctions] {
def apply[A](f: => A)(implicit T: ClassTag[T], NT: NotNull[T]): Validated[T, A] =
try {
valid(f)
} catch {
case t if T.runtimeClass.isInstance(t) =>
invalid(t.asInstanceOf[T])
}
}
}

def catchNonFatal[A](f: => A): Validated[Throwable, A] =
try {
valid(f)
} catch {
case scala.util.control.NonFatal(t) => invalid(t)
}

/**
* Converts a `Try[A]` to a `Validated[Throwable, A]`.
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/tut/traverse.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def parseIntXor(s: String): Xor[NumberFormatException, Int] =
Xor.catchOnly[NumberFormatException](s.toInt)
def parseIntValidated(s: String): ValidatedNel[NumberFormatException, Int] =
Validated.fromTryCatch[NumberFormatException](s.toInt).toValidatedNel
Validated.catchOnly[NumberFormatException](s.toInt).toValidatedNel
val x1 = List("1", "2", "3").traverseU(parseIntXor)
val x2 = List("1", "abc", "3").traverseU(parseIntXor)
Expand Down
13 changes: 9 additions & 4 deletions tests/src/test/scala/cats/tests/ValidatedTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,21 @@ class ValidatedTests extends CatsSuite {
Applicative[Validated[String, ?]].ap2(Invalid("1"), Invalid("2"))(Valid(plus)) should === (Invalid("12"))
}

test("fromTryCatch catches matching exceptions") {
assert(Validated.fromTryCatch[NumberFormatException]{ "foo".toInt }.isInstanceOf[Invalid[NumberFormatException]])
test("catchOnly catches matching exceptions") {
assert(Validated.catchOnly[NumberFormatException]{ "foo".toInt }.isInstanceOf[Invalid[NumberFormatException]])
}

test("fromTryCatch lets non-matching exceptions escape") {
test("catchOnly lets non-matching exceptions escape") {
val _ = intercept[NumberFormatException] {
Validated.fromTryCatch[IndexOutOfBoundsException]{ "foo".toInt }
Validated.catchOnly[IndexOutOfBoundsException]{ "foo".toInt }
}
}

test("catchNonFatal catches non-fatal exceptions") {
assert(Validated.catchNonFatal{ "foo".toInt }.isInvalid)
assert(Validated.catchNonFatal{ throw new Throwable("blargh") }.isInvalid)
}

test("fromTry is invalid for failed try"){
forAll { t: Try[Int] =>
t.isFailure should === (Validated.fromTry(t).isInvalid)
Expand Down
8 changes: 1 addition & 7 deletions tests/src/test/scala/cats/tests/XorTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,7 @@ class XorTests extends CatsSuite {

test("catchNonFatal catches non-fatal exceptions") {
assert(Xor.catchNonFatal{ "foo".toInt }.isLeft)
assert(Xor.catchNonFatal{ new Throwable("blargh") }.isLeft)
}

test("catchOnly lets non-matching exceptions escape") {
val _ = intercept[NumberFormatException] {
Xor.catchOnly[IndexOutOfBoundsException]{ "foo".toInt }
}
assert(Xor.catchNonFatal{ throw new Throwable("blargh") }.isLeft)
}

test("fromTry is left for failed Try") {
Expand Down

0 comments on commit 5411e93

Please sign in to comment.