Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ball and Chain: toSingleBox now sets up the failure chain properly. #1609

Merged
merged 1 commit into from
Dec 14, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions core/common/src/main/scala/net/liftweb/common/Box.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,43 @@ object Box extends BoxTrait {
**/
implicit class ListOfBoxes[T](val theListOfBoxes: List[Box[T]]) extends AnyVal {
/**
* Convert a List of Boxes into a single Box containting a List[T], where T is
* the parameterized type of the Boxes.
* Convert a `List` of `Box`es into a single `Box` containting a `List[T]`,
* where `T` is the parameterized type of the `Box`es.
*
* This method is useful for those cases where you have a lot of operations being
* executed that all return some Box[T]. You want just a List[T] if all of those
* operations succeeded, but you don't want to have Failures disappear if any were
* present in the list.
* This method is useful for those cases where you have a lot of operations
* being executed that all return some `Box[T]`. You want just a `List[T]`
* if all of those operations succeeded, but you don't want to have
* Failures disappear if any were present in the list.
*
* If all of the Boxes in the List are Full or Empty, we return a Full box containing
* a List of all of the Full Box values that were present. If any of the Boxes contain
* a Failure, a ParamFailure is returned, containing the original List[Box[T]] as the
* param.
* If all of the `Box`es in the `List` are `Full` or `Empty`, we return a
* `Full` box containing a `List` of all of the `Full` `Box` values that
* were present. If any of the `Box`es contain a `Failure`, a
* `ParamFailure` is returned, containing the original `List[Box[T]]` as
* the param. The `ParamFailure` itself is chained to a `Failure` chain
* containing all of the `Failure` boxes in the list.
*
* It is worth noting that the size of the list in the resulting Box[List[T]] may not be equal
* to the size of the List[Box[T]] that is fed as Empty values will disappear altogether in the
* conversion.
* It is worth noting that the size of the list in the resulting
* `Box[List[T]]` may not be equal to the size of the `List[Box[T]]` that
* is fed as `Empty` values will disappear altogether in the conversion.
*
* @param failureErrorMessage The string that should be placed in the message for the Failure.
* @return A Full[List[T]] if no Failures were present. ParamFailure[List[Box[T]]] otherwise.
* @return A `Full[List[T]]` if no `Failure`s were present. `ParamFailure[List[Box[T]]]` otherwise.
**/
def toSingleBox(failureErrorMessage: String): Box[List[T]] = {
if (theListOfBoxes.exists(_.isInstanceOf[Failure])) {
Failure(failureErrorMessage) ~> theListOfBoxes
val failureChain =
theListOfBoxes.collect {
case fail: Failure => fail
}.reduceRight { (topmostFailure, latestFailure) =>
topmostFailure.copy(chain = Full(latestFailure))
}

ParamFailure(
failureErrorMessage,
Empty,
Full(failureChain),
theListOfBoxes
)
} else {
Full(theListOfBoxes.flatten)
}
Expand Down
21 changes: 20 additions & 1 deletion core/common/src/test/scala/net/liftweb/common/BoxSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,26 @@ class BoxSpec extends Specification with ScalaCheck with BoxGenerator {
val someBoxes: List[Box[String]] = List(Full("bacon"), Full("sammich"), Failure("I HATE BACON"))
val singleBox = someBoxes.toSingleBox("This should be in the param failure.")

singleBox must_== ParamFailure("This should be in the param failure.", None, None, someBoxes)
singleBox must beLike {
case ParamFailure(message, _, _, _) =>
message must_== "This should be in the param failure."
}
}

"chain the ParamFailure to the failures in the list when any are Failure" in {
val someBoxes: List[Box[String]] = List(Full("bacon"), Failure("I HATE BACON"), Full("sammich"), Failure("MORE BACON FAIL"), Failure("BACON WHY U BACON"))

val singleBox = someBoxes.toSingleBox("Failure.")

val expectedChain =
Failure("I HATE BACON", Empty,
Full(Failure("MORE BACON FAIL", Empty,
Full(Failure("BACON WHY U BACON")))))

singleBox must beLike {
case ParamFailure(_, _, chain, _) =>
chain must_== Full(expectedChain)
}
}
}

Expand Down