I'm trying to wrap my head around how Spray has implemented their Directives, and in particular the Parameter extraction DSL.
I understand the magnet pattern (barely) but am stuck on how the ParamDefMagnet and ParamDefMagnet2 work together.
def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
trait ParamDefMagnet {
type Out
def apply(): Out
}
trait ParamDefMagnet2[T] {
type Out
def apply(value: T): Out
}
type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B }
def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) }
I'm trying to work out how a ParamDefManget2 is implicitly converted to a ParamDefMagnet by the the below implicit method.
object ParamDefMagnet {
implicit def apply[T](value: T)(implicit pdm2: ParamDefMagnet2[T]) = new ParamDefMagnet {
type Out = pdm2.Out
def apply() = pdm2(value)
}
}
If i call parameter("name"), how is "name" implicitly converted to a ParamDefMagnet? And if it converts it to a ParamDefMagnet2 first, then where does value: T come from in order to convert it to a ParamDefMagnet?
So after digging around with examples, I think i've finally got to the bottom of how the parameter function works:
An example for extracting a parameter of type String:
Spray uses a bunch of implicit conversions but basically, if you have a
Stringand aString => Directive1[String], you can construct a() => Directive1[String]:All of this is what constitutes the simple
parameter("name")call:For how a
Directive1[String]is applied in a DSL-ey way, see How do directives work in Spray?