Last active
August 29, 2015 14:11
-
-
Save gabro/a45bebbdd1a86f40005b to your computer and use it in GitHub Desktop.
Automatic get parameters generator from case class for spray routing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example | |
import scala.language.existentials | |
import shapeless._; import record._; import ops.record._; import ops.hlist._ | |
import spray.routing.SimpleRoutingApp | |
trait AutoGetParametersModule { self: SimpleRoutingApp => | |
import spray.routing.{ Directive, Directive1, Directive0, HListDeserializer } | |
import spray.routing.directives._ | |
// mimic partial inference | |
trait AsBuilder[L <: HList] { | |
def apply[A](ds: HListDeserializer[L, A]): Directive1[A] | |
} | |
// mimic partial inference | |
class ParamsBuilder[A] { | |
def apply[Repr <: HList, O <: HList, L <: HList](implicit | |
lgen: LabelledGeneric.Aux[A, Repr], | |
names: Names.Aux[Repr, O], | |
folder: LeftFolder.Aux[O, Directive0, ParamDefMagnet2.MapReduce.type, Directive[L]] | |
): AsBuilder[L] = new AsBuilder[L] { | |
def apply[A](ds: HListDeserializer[L, A]) = | |
parameters(names.apply).as(ds) | |
} | |
} | |
def params[A] = new ParamsBuilder[A] | |
/* type class for building an HList of NameReceptacle from a LabelledGeneric */ | |
trait Names[L <: HList] extends DepFn0 { type Out <: HList } | |
object Names { | |
def apply[L <: HList](implicit names: Names[L]): Aux[L, names.Out] = names | |
type Aux[L <: HList, Out0 <: HList] = Names[L] { type Out = Out0 } | |
implicit def hnilNames[L <: HNil]: Aux[L, HNil] = | |
new Names[L] { | |
type Out = HNil | |
def apply(): Out = HNil | |
} | |
implicit def hlistNames[K <: Symbol, V, T <: HList](implicit wk: Witness.Aux[K], nt: Names[T]): Aux[FieldType[K, V] :: T, NameReceptacle[V] :: nt.Out] = | |
new Names[FieldType[K, V] :: T] { | |
type Out = NameReceptacle[V] :: nt.Out | |
def apply(): Out = { | |
NameReceptacle[V](wk.value.name) :: nt() | |
} | |
} | |
} | |
} | |
object Main extends App with SimpleRoutingApp with AutoGetParametersModule { | |
implicit val system = akka.actor.ActorSystem("foo") | |
case class Foo(x: Option[String], y: Option[Boolean]) | |
val fooParams = params[Foo].apply | |
startServer(interface = "localhost", port = 8080) { | |
path("foo") { | |
fooParams(Foo) { foo => | |
complete(foo.toString) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
also,
Option
fields in the case class, can be left outproduces