diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2019-09-15 12:36:39 +0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2019-09-15 12:36:39 +0800 |
commit | 0e098a93da94c251eb05d42bc7ef48394600508c (patch) | |
tree | b4c3e7ec654e16aa50f149ce255ef187791461e7 | |
parent | 38c6a84a0e8fbc3debb93bbacaf8c092e675ecb3 (diff) | |
download | cask-0e098a93da94c251eb05d42bc7ef48394600508c.tar.gz cask-0e098a93da94c251eb05d42bc7ef48394600508c.tar.bz2 cask-0e098a93da94c251eb05d42bc7ef48394600508c.zip |
Break circular dependency by splitting `RouteEndpointMetadata` into its own file
-rw-r--r-- | cask/src/cask/main/Decorators.scala | 23 | ||||
-rw-r--r-- | cask/src/cask/main/Main.scala | 9 | ||||
-rw-r--r-- | cask/src/cask/main/Routes.scala | 70 | ||||
-rw-r--r-- | cask/src/cask/main/RoutesEndpointMetadata.scala | 68 | ||||
-rw-r--r-- | cask/src/cask/package.scala | 2 |
5 files changed, 88 insertions, 84 deletions
diff --git a/cask/src/cask/main/Decorators.scala b/cask/src/cask/main/Decorators.scala index 0a68cba..fb795ba 100644 --- a/cask/src/cask/main/Decorators.scala +++ b/cask/src/cask/main/Decorators.scala @@ -35,27 +35,28 @@ object Decorator{ * bindings passed from the router are aggregated with those from the `EndPoint` and * used as the first argument list. */ - def invoke(ctx: Request, - metadata: Routes.EndpointMetadata[_], - routes: Routes, - routeBindings: Map[String, String], - remainingDecorators: List[RawDecorator], - bindings: List[Map[String, Any]]): Router.Result[Any] = try { + def invoke[T](ctx: Request, + endpoint: Endpoint[_, _], + entryPoint: EntryPoint[T, _], + routes: T, + routeBindings: Map[String, String], + remainingDecorators: List[RawDecorator], + bindings: List[Map[String, Any]]): Router.Result[Any] = try { remainingDecorators match { case head :: rest => head.wrapFunction( ctx, - args => invoke(ctx, metadata, routes, routeBindings, rest, args :: bindings) + args => invoke(ctx, endpoint, entryPoint, routes, routeBindings, rest, args :: bindings) .asInstanceOf[Router.Result[cask.model.Response.Raw]] ) case Nil => - metadata.endpoint.wrapFunction(ctx, { (endpointBindings: Map[String, Any]) => - val mergedEndpointBindings = endpointBindings ++ routeBindings.mapValues(metadata.endpoint.wrapPathSegment) + endpoint.wrapFunction(ctx, { (endpointBindings: Map[String, Any]) => + val mergedEndpointBindings = endpointBindings ++ routeBindings.mapValues(endpoint.wrapPathSegment) val finalBindings = mergedEndpointBindings :: bindings - metadata.entryPoint - .asInstanceOf[EntryPoint[cask.main.Routes, cask.model.Request]] + entryPoint + .asInstanceOf[EntryPoint[T, cask.model.Request]] .invoke(routes, ctx, finalBindings) .asInstanceOf[Router.Result[Nothing]] }) diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala index fbcbff9..a5b4dc4 100644 --- a/cask/src/cask/main/Main.scala +++ b/cask/src/cask/main/Main.scala @@ -36,13 +36,13 @@ abstract class BaseMain{ lazy val routeList = for{ routes <- allRoutes - route <- routes.caskMetadata.value.map(x => x: Routes.EndpointMetadata[_]) + route <- routes.caskMetadata.value.map(x => x: EndpointMetadata[_]) } yield (routes, route) lazy val routeTries = Seq("get", "put", "post", "websocket") .map { method => - method -> DispatchTrie.construct[(Routes, Routes.EndpointMetadata[_])](0, + method -> DispatchTrie.construct[(Routes, EndpointMetadata[_])](0, for ((route, metadata) <- routeList if metadata.endpoint.methods.contains(method)) yield (Util.splitPath(metadata.endpoint.path): collection.IndexedSeq[String], (route, metadata), metadata.endpoint.subpath) ) @@ -91,7 +91,8 @@ abstract class BaseMain{ case Some(((routes, metadata), routeBindings, remaining)) => Decorator.invoke( Request(exchange, remaining), - metadata, + metadata.endpoint, + metadata.entryPoint.asInstanceOf[EntryPoint[Routes, _]], routes, routeBindings, (mainDecorators ++ routes.decorators ++ metadata.decorators).toList, @@ -123,7 +124,7 @@ abstract class BaseMain{ def handleEndpointError(exchange: HttpServerExchange, routes: Routes, - metadata: Routes.EndpointMetadata[_], + metadata: EndpointMetadata[_], e: Router.Result.Error) = { val statusCode = e match { case _: Router.Result.Error.Exception => 500 diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala index a6bdd65..be33581 100644 --- a/cask/src/cask/main/Routes.scala +++ b/cask/src/cask/main/Routes.scala @@ -1,84 +1,18 @@ package cask.main -import cask.internal.Router.EntryPoint -import scala.reflect.macros.blackbox.Context import language.experimental.macros -object Routes{ - case class EndpointMetadata[T](decorators: Seq[RawDecorator], - endpoint: Endpoint[_, _], - entryPoint: EntryPoint[T, _]) - case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) - object RoutesEndpointsMetadata{ - implicit def initialize[T]: RoutesEndpointsMetadata[T] = macro initializeImpl[T] - implicit def initializeImpl[T: c.WeakTypeTag](c: Context): c.Expr[RoutesEndpointsMetadata[T]] = { - import c.universe._ - val router = new cask.internal.Router[c.type](c) - - val routeParts = for{ - m <- c.weakTypeOf[T].members - annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]) - if annotations.nonEmpty - } yield { - if(!(annotations.last.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort( - annotations.head.tree.pos, - s"Last annotation applied to a function must be an instance of Endpoint, " + - s"not ${annotations.last.tree.tpe}" - ) - val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[Endpoint[_, _]]) - if(allEndpoints.length > 1) c.abort( - annotations.last.tree.pos, - s"You can only apply one Endpoint annotation to a function, not " + - s"${allEndpoints.length} in ${allEndpoints.map(_.tree.tpe).mkString(", ")}" - ) - - val annotObjects = - for(annot <- annotations) - yield q"new ${annot.tree.tpe}(..${annot.tree.children.tail})" - - val annotObjectSyms = - for(_ <- annotations.indices) - yield c.universe.TermName(c.freshName("annotObject")) - - val route = router.extractMethod( - m.asInstanceOf[MethodSymbol], - weakTypeOf[T], - q"${annotObjectSyms.last}.convertToResultType", - tq"cask.Request", - annotObjectSyms.reverse.map(annotObjectSym => q"$annotObjectSym.getParamParser"), - annotObjectSyms.reverse.map(annotObjectSym => tq"$annotObjectSym.InputTypeAlias") - ) - - val declarations = - for((sym, obj) <- annotObjectSyms.zip(annotObjects)) - yield q"val $sym = $obj" - - val res = q"""{ - ..$declarations - cask.main.Routes.EndpointMetadata( - Seq(..${annotObjectSyms.dropRight(1)}), - ${annotObjectSyms.last}, - $route - ) - }""" - res - } - - c.Expr[RoutesEndpointsMetadata[T]](q"""cask.main.Routes.RoutesEndpointsMetadata(..$routeParts)""") - } - } -} trait Routes{ def decorators = Seq.empty[cask.main.RawDecorator] - private[this] var metadata0: Routes.RoutesEndpointsMetadata[this.type] = null + private[this] var metadata0: RoutesEndpointsMetadata[this.type] = null def caskMetadata = if (metadata0 != null) metadata0 else throw new Exception("Routes not yet initialize") - protected[this] def initialize()(implicit routes: Routes.RoutesEndpointsMetadata[this.type]): Unit = { + protected[this] def initialize()(implicit routes: RoutesEndpointsMetadata[this.type]): Unit = { metadata0 = routes } } diff --git a/cask/src/cask/main/RoutesEndpointMetadata.scala b/cask/src/cask/main/RoutesEndpointMetadata.scala new file mode 100644 index 0000000..fa93a0c --- /dev/null +++ b/cask/src/cask/main/RoutesEndpointMetadata.scala @@ -0,0 +1,68 @@ +package cask.main + +import cask.internal.Router.EntryPoint + +import language.experimental.macros +import scala.reflect.macros.blackbox +case class EndpointMetadata[T](decorators: Seq[RawDecorator], + endpoint: Endpoint[_, _], + entryPoint: EntryPoint[T, _]) +case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) +object RoutesEndpointsMetadata{ + implicit def initialize[T]: RoutesEndpointsMetadata[T] = macro initializeImpl[T] + implicit def initializeImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[RoutesEndpointsMetadata[T]] = { + import c.universe._ + val router = new cask.internal.Router[c.type](c) + + val routeParts = for{ + m <- c.weakTypeOf[T].members + annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]) + if annotations.nonEmpty + } yield { + if(!(annotations.last.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort( + annotations.head.tree.pos, + s"Last annotation applied to a function must be an instance of Endpoint, " + + s"not ${annotations.last.tree.tpe}" + ) + val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[Endpoint[_, _]]) + if(allEndpoints.length > 1) c.abort( + annotations.last.tree.pos, + s"You can only apply one Endpoint annotation to a function, not " + + s"${allEndpoints.length} in ${allEndpoints.map(_.tree.tpe).mkString(", ")}" + ) + + val annotObjects = + for(annot <- annotations) + yield q"new ${annot.tree.tpe}(..${annot.tree.children.tail})" + + val annotObjectSyms = + for(_ <- annotations.indices) + yield c.universe.TermName(c.freshName("annotObject")) + + val route = router.extractMethod( + m.asInstanceOf[MethodSymbol], + weakTypeOf[T], + q"${annotObjectSyms.last}.convertToResultType", + tq"cask.Request", + annotObjectSyms.reverse.map(annotObjectSym => q"$annotObjectSym.getParamParser"), + annotObjectSyms.reverse.map(annotObjectSym => tq"$annotObjectSym.InputTypeAlias") + ) + + val declarations = + for((sym, obj) <- annotObjectSyms.zip(annotObjects)) + yield q"val $sym = $obj" + + val res = q"""{ + ..$declarations + cask.main.EndpointMetadata( + Seq(..${annotObjectSyms.dropRight(1)}), + ${annotObjectSyms.last}, + $route + ) + }""" + res + } + + c.Expr[RoutesEndpointsMetadata[T]](q"""cask.main.RoutesEndpointsMetadata(..$routeParts)""") + } +}
\ No newline at end of file diff --git a/cask/src/cask/package.scala b/cask/src/cask/package.scala index f55d33d..f72e14b 100644 --- a/cask/src/cask/package.scala +++ b/cask/src/cask/package.scala @@ -35,7 +35,7 @@ package object cask { // main type MainRoutes = main.MainRoutes type Routes = main.Routes - val Routes = main.Routes + type Main = main.Main type RawDecorator = main.RawDecorator type HttpEndpoint[InnerReturned, Input] = main.HttpEndpoint[InnerReturned, Input] |