From 329dd64ca0086680bcaac63587656c5464247692 Mon Sep 17 00:00:00 2001 From: Michael McKibben Date: Wed, 24 Dec 2014 15:25:22 -0700 Subject: [PATCH] = spray-routing: fix issue #981 = spray-routing-tests: add additional test cases for issue #981 --- .../routing/AnyParamDirectivesSpec.scala | 22 ++++ .../directives/AnyParamDirectives.scala | 102 ++++++++++-------- 2 files changed, 82 insertions(+), 42 deletions(-) diff --git a/spray-routing-tests/src/test/scala/spray/routing/AnyParamDirectivesSpec.scala b/spray-routing-tests/src/test/scala/spray/routing/AnyParamDirectivesSpec.scala index dac751ee72..fa903dc4e8 100644 --- a/spray-routing-tests/src/test/scala/spray/routing/AnyParamDirectivesSpec.scala +++ b/spray-routing-tests/src/test/scala/spray/routing/AnyParamDirectivesSpec.scala @@ -69,6 +69,28 @@ class AnyParamDirectivesSpec extends RoutingSpec { } } + "when used with a single parameter with default value" should { + val route = anyParam("x" ? "default") { echoComplete } + + "extract the parameter from query parameters" in { + Get("/test?x=specified") ~> route ~> check { + responseAs[String] === "specified" + } + } + + "extract the parameter from form" in { + Post("/test", FormData(Map("x" -> "specified"))) ~> route ~> check { + responseAs[String] === "specified" + } + } + + "extract default parameter value" in { + Get("/test") ~> route ~> check { + responseAs[String] === "default" + } + } + } + "when used with two required parameters" should { val route = (path("test") & anyParam("x", "y")) { echoComplete2 } diff --git a/spray-routing/src/main/scala/spray/routing/directives/AnyParamDirectives.scala b/spray-routing/src/main/scala/spray/routing/directives/AnyParamDirectives.scala index ad949bcbfb..a3e98f850d 100644 --- a/spray-routing/src/main/scala/spray/routing/directives/AnyParamDirectives.scala +++ b/spray-routing/src/main/scala/spray/routing/directives/AnyParamDirectives.scala @@ -45,28 +45,11 @@ trait AnyParamDefMagnet { } object AnyParamDefMagnet { - private type APDM2Tuple1[T] = AnyParamDefMagnet2[Tuple1[T]] - private def apply[T](value: T)(implicit apdm2Tuple1: APDM2Tuple1[T]) = + implicit def apply[T](value: T)(implicit apdm2: AnyParamDefMagnet2[T]) = new AnyParamDefMagnet { - type Out = apdm2Tuple1.Out - def apply() = apdm2Tuple1(Tuple1(value)) - } - - implicit def forString[T <: String](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forSymbol[T <: Symbol](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forNR[T <: NameReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forNDesR[T <: NameDeserializerReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forNDefR[T <: NameDefaultReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forNDesDefR[T <: NameDeserializerDefaultReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - - implicit def forRVR[T <: RequiredValueReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - implicit def forRVDR[T <: RequiredValueDeserializerReceptacle[_]](value: T)(implicit apdm2: APDM2Tuple1[T]) = apply(value) - - implicit def forTuple[T <: Product](value: T)(implicit apdm21: AnyParamDefMagnet2[T]) = - new AnyParamDefMagnet { - type Out = apdm21.Out - def apply() = apdm21(value) + type Out = apdm2.Out + def apply() = apdm2(value) } } @@ -79,33 +62,68 @@ object AnyParamDefMagnet2 { import FieldDefMagnet2.FieldDefMagnetAux import ParamDefMagnet2.ParamDefMagnetAux - implicit def forTuple[T <: Product, L <: HList, Out](implicit hla: HListerAux[T, L], - apdma: AnyParamDefMagnet2[L]) = - new AnyParamDefMagnet2[T] { - def apply(value: T) = apdma(hla(value)) - type Out = apdma.Out - } + type AnyParamDefMagnetAux[A, B] = AnyParamDefMagnet2[A] { type Out = B } + def AnyParamDefMagnetAux[A, B](f: A ⇒ B) = new AnyParamDefMagnet2[A] { type Out = B; def apply(a: A) = f(a) } + + private def extractAnyParam[A, B](f: A ⇒ Directive1[B]) = AnyParamDefMagnetAux[A, Directive1[B]](f) + + private def anyParamWrapper[A, B](a: A)(implicit fdma: FieldDefMagnetAux[A, Directive1[B]], pdma: ParamDefMagnetAux[A, Directive1[B]]): Directive1[B] = { + // handle optional params + // see https://groups.google.com/forum/?fromgroups=#!topic/spray-user/HGEEdVajpUw + fdma(a).hflatMap { + case None :: HNil ⇒ pdma(a) + case x ⇒ BasicDirectives.hprovide(x) + } | pdma(a) + } + + private def anyParamDefaultWrapper[A, B](a: A, default: ⇒ B)(implicit fdma: FieldDefMagnetAux[A, Directive1[B]], pdma: ParamDefMagnetAux[A, Directive1[B]]): Directive1[B] = + anyParamWrapper(a).hflatMap { + case None :: HNil ⇒ BasicDirectives.provide(default) + case x ⇒ BasicDirectives.hprovide(x) + } | BasicDirectives.provide(default) + + implicit def forString(implicit fdma: FieldDefMagnetAux[String, Directive1[String]], pdma: ParamDefMagnetAux[String, Directive1[String]]) = { + extractAnyParam[String, String](anyParamWrapper(_)) + } + + implicit def forSymbol(implicit fdma: FieldDefMagnetAux[Symbol, Directive1[String]], pdma: ParamDefMagnetAux[Symbol, Directive1[String]]) = { + extractAnyParam[Symbol, String](anyParamWrapper(_)) + } + + implicit def forNR[T](implicit fdma: FieldDefMagnetAux[NameReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[NameReceptacle[T], Directive1[T]]) = { + extractAnyParam[NameReceptacle[T], T](anyParamWrapper(_)) + } + + implicit def forNDefR[T](implicit fdma: FieldDefMagnetAux[NameReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[NameReceptacle[T], Directive1[T]]) = { + extractAnyParam[NameDefaultReceptacle[T], T](t ⇒ anyParamDefaultWrapper(NameReceptacle[T](t.name), t.default)) + } + + implicit def forNDesR[T](implicit fdma: FieldDefMagnetAux[NameDeserializerReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[NameDeserializerReceptacle[T], Directive1[T]]) = { + extractAnyParam[NameDeserializerReceptacle[T], T](anyParamWrapper(_)) + } + + implicit def forNDesDefR[T](implicit fdma: FieldDefMagnetAux[NameDeserializerReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[NameDeserializerReceptacle[T], Directive1[T]]) = { + extractAnyParam[NameDeserializerDefaultReceptacle[T], T](t ⇒ anyParamDefaultWrapper(NameDeserializerReceptacle[T](t.name, t.deserializer), t.default)) + } + + implicit def forRVR[T](implicit fdma: FieldDefMagnetAux[RequiredValueReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[RequiredValueReceptacle[T], Directive1[T]]) = { + extractAnyParam[RequiredValueReceptacle[T], T](anyParamWrapper(_)) + } + + implicit def forRVDR[T](value: T)(implicit fdma: FieldDefMagnetAux[RequiredValueDeserializerReceptacle[T], Directive1[T]], pdma: ParamDefMagnetAux[RequiredValueDeserializerReceptacle[T], Directive1[T]]) = { + extractAnyParam[RequiredValueDeserializerReceptacle[T], T](anyParamWrapper(_)) + } + + implicit def forTuple[T <: Product, L <: HList, Out0](implicit hla: HListerAux[T, L], pdma: AnyParamDefMagnetAux[L, Out0]) = + AnyParamDefMagnetAux[T, Out0](tuple ⇒ pdma(hla(tuple))) implicit def forHList[L <: HList](implicit f: LeftFolder[L, Directive0, MapReduce.type]) = - new AnyParamDefMagnet2[L] { - type Out = f.Out - def apply(value: L) = { - value.foldLeft(BasicDirectives.noop)(MapReduce) - } - } + AnyParamDefMagnetAux[L, f.Out](_.foldLeft(BasicDirectives.noop)(MapReduce)) object MapReduce extends Poly2 { - implicit def from[T, LA <: HList, LB <: HList, Out <: HList](implicit fdma: FieldDefMagnetAux[T, Directive[LB]], - pdma: ParamDefMagnetAux[T, Directive[LB]], - ev: PrependAux[LA, LB, Out]) = { - // see https://groups.google.com/forum/?fromgroups=#!topic/spray-user/HGEEdVajpUw - def fdmaWrapper(t: T): Directive[LB] = fdma(t).hflatMap { - case None :: HNil ⇒ pdma(t) - case x ⇒ BasicDirectives.hprovide(x) - } + implicit def from[T, LA <: HList, LB <: HList, Out <: HList](implicit pdma: AnyParamDefMagnetAux[T, Directive[LB]], ev: PrependAux[LA, LB, Out]) = + at[Directive[LA], T] { (a, t) ⇒ a & pdma(t) } - at[Directive[LA], T] { (a, t) ⇒ a & (fdmaWrapper(t) | pdma(t)) } - } } }