From 70dbe3ed561172a80ebff0515e727434b03040bf Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 9 Oct 2019 10:54:16 +0800 Subject: Convert `Decorator#OuterReturned` into a type parameter --- cask/src/cask/endpoints/JsonEndpoint.scala | 4 ++-- cask/src/cask/endpoints/StaticEndpoints.scala | 6 +++--- cask/src/cask/endpoints/WebSocketEndpoint.scala | 4 ++-- cask/src/cask/main/Main.scala | 4 ++-- cask/src/cask/main/Routes.scala | 2 +- cask/src/cask/router/Decorators.scala | 21 +++++++++------------ cask/src/cask/router/RoutesEndpointMetadata.scala | 8 ++++---- cask/test/src/test/cask/FailureTests.scala | 2 +- example/decorated/app/src/Decorated.scala | 4 ++-- example/decorated2/app/src/Decorated2.scala | 4 ++-- example/endpoints/app/src/Endpoints.scala | 2 +- example/todo/app/src/TodoServer.scala | 2 +- example/todoDb/app/src/TodoMvcDb.scala | 2 +- 13 files changed, 31 insertions(+), 34 deletions(-) diff --git a/cask/src/cask/endpoints/JsonEndpoint.scala b/cask/src/cask/endpoints/JsonEndpoint.scala index 31109d9..098bc82 100644 --- a/cask/src/cask/endpoints/JsonEndpoint.scala +++ b/cask/src/cask/endpoints/JsonEndpoint.scala @@ -44,7 +44,7 @@ class postJson(val path: String, override val subpath: Boolean = false) extends HttpEndpoint[Response[JsonData], ujson.Value]{ val methods = Seq("post") type InputParser[T] = JsReader[T] - override type OuterReturned = Result[Response.Raw] + def wrapFunction(ctx: Request, delegate: Delegate): Result[Response.Raw] = { val obj = for{ @@ -83,7 +83,7 @@ class getJson(val path: String, override val subpath: Boolean = false) extends HttpEndpoint[Response[JsonData], Seq[String]]{ val methods = Seq("get") type InputParser[T] = QueryParamReader[T] - override type OuterReturned = Result[Response.Raw] + def wrapFunction(ctx: Request, delegate: Delegate): Result[Response.Raw] = { delegate(WebEndpoint.buildMapFromQueryParams(ctx)) } diff --git a/cask/src/cask/endpoints/StaticEndpoints.scala b/cask/src/cask/endpoints/StaticEndpoints.scala index 618da5f..c36551b 100644 --- a/cask/src/cask/endpoints/StaticEndpoints.scala +++ b/cask/src/cask/endpoints/StaticEndpoints.scala @@ -1,6 +1,6 @@ package cask.endpoints -import cask.router.HttpEndpoint +import cask.router.{HttpEndpoint, Result} import cask.model.Request object StaticUtil{ def makePath(t: String, ctx: Request) = { @@ -14,7 +14,7 @@ class staticFiles(val path: String, headers: Seq[(String, String)] = Nil) extend val methods = Seq("get") type InputParser[T] = QueryParamReader[T] override def subpath = true - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map()).map(t => cask.model.StaticFile(StaticUtil.makePath(t, ctx), headers)) } @@ -28,7 +28,7 @@ class staticResources(val path: String, val methods = Seq("get") type InputParser[T] = QueryParamReader[T] override def subpath = true - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map()).map(t => cask.model.StaticResource(StaticUtil.makePath(t, ctx), resourceRoot, headers) ) diff --git a/cask/src/cask/endpoints/WebSocketEndpoint.scala b/cask/src/cask/endpoints/WebSocketEndpoint.scala index 994f015..905c5f1 100644 --- a/cask/src/cask/endpoints/WebSocketEndpoint.scala +++ b/cask/src/cask/endpoints/WebSocketEndpoint.scala @@ -21,11 +21,11 @@ object WebsocketResult{ } class websocket(val path: String, override val subpath: Boolean = false) - extends cask.router.Endpoint[WebsocketResult, Seq[String]]{ + extends cask.router.Endpoint[WebsocketResult, WebsocketResult, Seq[String]]{ val methods = Seq("websocket") type InputParser[T] = QueryParamReader[T] type OuterReturned = Result[WebsocketResult] - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(WebEndpoint.buildMapFromQueryParams(ctx)) } diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala index 0bc1abf..a96d706 100644 --- a/cask/src/cask/main/Main.scala +++ b/cask/src/cask/main/Main.scala @@ -27,7 +27,7 @@ class MainRoutes extends Main with Routes{ * application-wide properties. */ abstract class Main{ - def mainDecorators: Seq[Decorator[_, _]] = Nil + def mainDecorators: Seq[Decorator[_, _, _]] = Nil def allRoutes: Seq[Routes] def port: Int = 8080 def host: String = "localhost" @@ -61,7 +61,7 @@ abstract class Main{ object Main{ class DefaultHandler(routeTries: Map[String, DispatchTrie[(Routes, EndpointMetadata[_])]], - mainDecorators: Seq[Decorator[_, _]], + mainDecorators: Seq[Decorator[_, _, _]], debugMode: Boolean, handleNotFound: () => Response.Raw, handleError: (Routes, EndpointMetadata[_], Result.Error) => Response.Raw) diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala index 59da2c7..1b83be3 100644 --- a/cask/src/cask/main/Routes.scala +++ b/cask/src/cask/main/Routes.scala @@ -6,7 +6,7 @@ import language.experimental.macros trait Routes{ - def decorators = Seq.empty[cask.router.Decorator[_, _]] + def decorators = Seq.empty[cask.router.Decorator[_, _, _]] implicit def executionContext = concurrent.ExecutionContext.Implicits.global private[this] var metadata0: RoutesEndpointsMetadata[this.type] = null def caskMetadata = diff --git a/cask/src/cask/router/Decorators.scala b/cask/src/cask/router/Decorators.scala index d661177..895be53 100644 --- a/cask/src/cask/router/Decorators.scala +++ b/cask/src/cask/router/Decorators.scala @@ -14,12 +14,11 @@ import cask.model.{Request, Response} * to `wrapFunction`, which takes a `Map` representing any additional argument * lists (if any). */ -trait Decorator[InnerReturned, Input]{ +trait Decorator[OuterReturned, InnerReturned, Input]{ final type InputTypeAlias = Input type InputParser[T] <: ArgReader[Input, T, Request] final type Delegate = Map[String, Input] => Result[InnerReturned] - type OuterReturned <: Result[Any] - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned + def wrapFunction(ctx: Request, delegate: Delegate): Result[OuterReturned] def getParamParser[T](implicit p: InputParser[T]) = p } object Decorator{ @@ -35,15 +34,15 @@ object Decorator{ * used as the first argument list. */ def invoke[T](ctx: Request, - endpoint: Endpoint[_, _], + endpoint: Endpoint[_, _, _], entryPoint: EntryPoint[T, _], routes: T, routeBindings: Map[String, String], - remainingDecorators: List[Decorator[_, _]], + remainingDecorators: List[Decorator[_, _, _]], bindings: List[Map[String, Any]]): Result[Any] = try { remainingDecorators match { case head :: rest => - head.asInstanceOf[Decorator[Any, Any]].wrapFunction( + head.asInstanceOf[Decorator[Any, Any, Any]].wrapFunction( ctx, args => invoke(ctx, endpoint, entryPoint, routes, routeBindings, rest, args :: bindings) .asInstanceOf[Result[Nothing]] @@ -70,8 +69,7 @@ object Decorator{ * A [[RawDecorator]] is a decorator that operates on the raw request and * response stream, before and after the primary [[Endpoint]] does it's job. */ -trait RawDecorator extends Decorator[Response.Raw, Any]{ - type OuterReturned = Result[Response.Raw] +trait RawDecorator extends Decorator[Response.Raw, Response.Raw, Any]{ type InputParser[T] = NoOpParser[Any, T] } @@ -80,7 +78,8 @@ trait RawDecorator extends Decorator[Response.Raw, Any]{ * An [[HttpEndpoint]] that may return something else than a HTTP response, e.g. * a websocket endpoint which may instead return a websocket event handler */ -trait Endpoint[InnerReturned, Input] extends Decorator[InnerReturned, Input]{ +trait Endpoint[OuterReturned, InnerReturned, Input] + extends Decorator[OuterReturned, InnerReturned, Input]{ /** * What is the path that this particular endpoint matches? */ @@ -119,9 +118,7 @@ trait Endpoint[InnerReturned, Input] extends Decorator[InnerReturned, Input]{ * Annotates a Cask endpoint that returns a HTTP [[Response]]; similar to a * [[RawDecorator]] but with additional metadata and capabilities. */ -trait HttpEndpoint[InnerReturned, Input] extends Endpoint[InnerReturned, Input] { - type OuterReturned = Result[Response.Raw] -} +trait HttpEndpoint[InnerReturned, Input] extends Endpoint[Response.Raw, InnerReturned, Input] class NoOpParser[Input, T] extends ArgReader[Input, T, Request] { diff --git a/cask/src/cask/router/RoutesEndpointMetadata.scala b/cask/src/cask/router/RoutesEndpointMetadata.scala index 7940641..2445c9d 100644 --- a/cask/src/cask/router/RoutesEndpointMetadata.scala +++ b/cask/src/cask/router/RoutesEndpointMetadata.scala @@ -5,7 +5,7 @@ import cask.router.EntryPoint import language.experimental.macros import scala.reflect.macros.blackbox case class EndpointMetadata[T](decorators: Seq[RawDecorator], - endpoint: Endpoint[_, _], + endpoint: Endpoint[_, _, _], entryPoint: EntryPoint[T, _]) case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) object RoutesEndpointsMetadata{ @@ -16,15 +16,15 @@ object RoutesEndpointsMetadata{ val routeParts = for{ m <- c.weakTypeOf[T].members - annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]) + annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _, _]]) if annotations.nonEmpty } yield { - if(!(annotations.last.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort( + 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[_, _]]) + 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 " + diff --git a/cask/test/src/test/cask/FailureTests.scala b/cask/test/src/test/cask/FailureTests.scala index 25530fa..bd27971 100644 --- a/cask/test/src/test/cask/FailureTests.scala +++ b/cask/test/src/test/cask/FailureTests.scala @@ -5,7 +5,7 @@ import utest._ object FailureTests extends TestSuite { class myDecorator extends cask.RawDecorator { - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map("extra" -> 31337)) } } diff --git a/example/decorated/app/src/Decorated.scala b/example/decorated/app/src/Decorated.scala index a88bd2e..6649988 100644 --- a/example/decorated/app/src/Decorated.scala +++ b/example/decorated/app/src/Decorated.scala @@ -4,12 +4,12 @@ object Decorated extends cask.MainRoutes{ override def toString = "[haoyi]" } class loggedIn extends cask.RawDecorator { - def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: cask.Request, delegate: Delegate) = { delegate(Map("user" -> new User())) } } class withExtra extends cask.RawDecorator { - def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: cask.Request, delegate: Delegate) = { delegate(Map("extra" -> 31337)) } } diff --git a/example/decorated2/app/src/Decorated2.scala b/example/decorated2/app/src/Decorated2.scala index 305281a..4a3b9cc 100644 --- a/example/decorated2/app/src/Decorated2.scala +++ b/example/decorated2/app/src/Decorated2.scala @@ -4,12 +4,12 @@ object Decorated2 extends cask.MainRoutes{ override def toString = "[haoyi]" } class loggedIn extends cask.RawDecorator { - def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: cask.Request, delegate: Delegate) = { delegate(Map("user" -> new User())) } } class withExtra extends cask.RawDecorator { - def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: cask.Request, delegate: Delegate) = { delegate(Map("extra" -> 31337)) } } diff --git a/example/endpoints/app/src/Endpoints.scala b/example/endpoints/app/src/Endpoints.scala index 9722673..f59983c 100644 --- a/example/endpoints/app/src/Endpoints.scala +++ b/example/endpoints/app/src/Endpoints.scala @@ -2,7 +2,7 @@ package app class custom(val path: String, val methods: Seq[String]) extends cask.HttpEndpoint[Int, Seq[String]]{ - def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: cask.Request, delegate: Delegate) = { delegate(Map()).map{num => cask.Response("Echo " + num, statusCode = num) } diff --git a/example/todo/app/src/TodoServer.scala b/example/todo/app/src/TodoServer.scala index 2df6fb2..8b498b5 100644 --- a/example/todo/app/src/TodoServer.scala +++ b/example/todo/app/src/TodoServer.scala @@ -16,7 +16,7 @@ object TodoServer extends cask.MainRoutes{ class transactional extends cask.RawDecorator{ class TransactionFailed(val value: cask.router.Result.Error) extends Exception - def wrapFunction(pctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(pctx: cask.Request, delegate: Delegate) = { try ctx.transaction( delegate(Map()) match{ case cask.router.Result.Success(t) => cask.router.Result.Success(t) diff --git a/example/todoDb/app/src/TodoMvcDb.scala b/example/todoDb/app/src/TodoMvcDb.scala index 0bb25c0..66109f4 100644 --- a/example/todoDb/app/src/TodoMvcDb.scala +++ b/example/todoDb/app/src/TodoMvcDb.scala @@ -15,7 +15,7 @@ object TodoMvcDb extends cask.MainRoutes{ class transactional extends cask.RawDecorator{ class TransactionFailed(val value: cask.router.Result.Error) extends Exception - def wrapFunction(pctx: cask.Request, delegate: Delegate): OuterReturned = { + def wrapFunction(pctx: cask.Request, delegate: Delegate) = { try ctx.transaction( delegate(Map()) match{ case cask.router.Result.Success(t) => cask.router.Result.Success(t) -- cgit v1.2.3