From 9326dfd92a9fc120c2cdd892575486193281fb26 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 26 Jul 2018 10:31:40 +0800 Subject: Simplify public Decorator API --- cask/src/cask/endpoints/FormEndpoint.scala | 7 +++-- cask/src/cask/endpoints/JsonEndpoint.scala | 4 +-- cask/src/cask/endpoints/StaticEndpoints.scala | 4 +-- cask/src/cask/endpoints/WebEndpoints.scala | 4 +-- cask/src/cask/main/Main.scala | 7 ++--- cask/src/cask/main/Routes.scala | 38 ++++++++++++++++++++------- cask/src/cask/package.scala | 1 + cask/test/src/test/cask/Decorated.scala | 17 ++++++++++++ cask/test/src/test/cask/Decorator.scala | 26 ------------------ cask/test/src/test/cask/ExampleTests.scala | 2 +- 10 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 cask/test/src/test/cask/Decorated.scala delete mode 100644 cask/test/src/test/cask/Decorator.scala (limited to 'cask') diff --git a/cask/src/cask/endpoints/FormEndpoint.scala b/cask/src/cask/endpoints/FormEndpoint.scala index 99699e6..f042d74 100644 --- a/cask/src/cask/endpoints/FormEndpoint.scala +++ b/cask/src/cask/endpoints/FormEndpoint.scala @@ -35,12 +35,11 @@ object FormReader{ } } class postForm(val path: String, override val subpath: Boolean = false) extends Routes.Endpoint[Response]{ + val methods = Seq("post") type InputType = Seq[FormValue] - def parseMethodInput[T](implicit p: FormReader[T]) = p - - - def handle(ctx: ParamContext) = { + type InputParser[T] = FormReader[T] + def getParamValues(ctx: ParamContext) = { val formData = FormParserFactory.builder().build().createParser(ctx.exchange).parseBlocking() val formDataBindings = formData diff --git a/cask/src/cask/endpoints/JsonEndpoint.scala b/cask/src/cask/endpoints/JsonEndpoint.scala index f740148..19c7b8a 100644 --- a/cask/src/cask/endpoints/JsonEndpoint.scala +++ b/cask/src/cask/endpoints/JsonEndpoint.scala @@ -27,8 +27,8 @@ object JsReader{ class postJson(val path: String, override val subpath: Boolean = false) extends Routes.Endpoint[Response]{ val methods = Seq("post") type InputType = ujson.Js.Value - def parseMethodInput[T](implicit p: JsReader[T]) = p - def handle(ctx: ParamContext) = + type InputParser[T] = JsReader[T] + def getParamValues(ctx: ParamContext) = ujson.read(new String(ctx.exchange.getInputStream.readAllBytes())).obj.toMap def wrapPathSegment(s: String): InputType = ujson.Js.Str(s) } diff --git a/cask/src/cask/endpoints/StaticEndpoints.scala b/cask/src/cask/endpoints/StaticEndpoints.scala index f644d86..a88781e 100644 --- a/cask/src/cask/endpoints/StaticEndpoints.scala +++ b/cask/src/cask/endpoints/StaticEndpoints.scala @@ -7,13 +7,13 @@ import cask.model.ParamContext class static(val path: String) extends Routes.Endpoint[String] { val methods = Seq("get") type InputType = Seq[String] + type InputParser[T] = QueryParamReader[T] override def subpath = true def wrapOutput(t: String) = t - def parseMethodInput[T](implicit p: QueryParamReader[T]) = p override def wrapMethodOutput(ctx: ParamContext, t: String) = { Router.Result.Success(cask.model.Static(t + "/" + ctx.remaining.mkString("/"))) } - def handle(ctx: ParamContext) = Map() + def getParamValues(ctx: ParamContext) = Map() def wrapPathSegment(s: String): InputType = Seq(s) } diff --git a/cask/src/cask/endpoints/WebEndpoints.scala b/cask/src/cask/endpoints/WebEndpoints.scala index 9eca964..1885475 100644 --- a/cask/src/cask/endpoints/WebEndpoints.scala +++ b/cask/src/cask/endpoints/WebEndpoints.scala @@ -10,8 +10,8 @@ import collection.JavaConverters._ trait WebEndpoint extends Routes.Endpoint[BaseResponse]{ type InputType = Seq[String] - def parseMethodInput[T](implicit p: QueryParamReader[T]) = p - def handle(ctx: ParamContext) = ctx.exchange.getQueryParameters + type InputParser[T] = QueryParamReader[T] + def getParamValues(ctx: ParamContext) = ctx.exchange.getQueryParameters .asScala .map{case (k, vs) => (k, vs.asScala.toArray.toSeq)} .toMap diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala index 8e21e2e..763b12a 100644 --- a/cask/src/cask/main/Main.scala +++ b/cask/src/cask/main/Main.scala @@ -1,7 +1,5 @@ package cask.main -import java.io.{PrintWriter, StringWriter} - import cask.model._ import cask.internal.Router.EntryPoint import cask.internal.{DispatchTrie, Router, Util} @@ -9,7 +7,6 @@ import io.undertow.Undertow import io.undertow.server.{HttpHandler, HttpServerExchange} import io.undertow.server.handlers.BlockingHandler import io.undertow.util.HttpString -import fastparse.utils.Utils.literalize class MainRoutes extends BaseMain with Routes{ def allRoutes = Seq(this) @@ -60,9 +57,9 @@ abstract class BaseMain{ case None => writeResponse(exchange, handleError(404)) case Some(((routes, metadata), bindings, remaining)) => val providers = - Seq(metadata.endpoint.handle(ParamContext(exchange, remaining)) ++ + Seq(metadata.endpoint.getParamValues(ParamContext(exchange, remaining)) ++ bindings.mapValues(metadata.endpoint.wrapPathSegment)) ++ - metadata.decorators.map(e => e.handle(ParamContext(exchange, remaining))) + metadata.decorators.map(e => e.getParamValues(ParamContext(exchange, remaining))) val result = metadata.entryPoint .asInstanceOf[EntryPoint[cask.main.Routes, cask.model.ParamContext]] diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala index 548162d..6f5b454 100644 --- a/cask/src/cask/main/Routes.scala +++ b/cask/src/cask/main/Routes.scala @@ -1,7 +1,7 @@ package cask.main import cask.internal.Router -import cask.internal.Router.EntryPoint +import cask.internal.Router.{ArgReader, EntryPoint} import cask.model.{BaseResponse, ParamContext} import scala.reflect.macros.blackbox.Context @@ -9,21 +9,41 @@ import language.experimental.macros object Routes{ - trait Endpoint[R] extends Decorator{ - type InputType + trait Endpoint[R] extends BaseDecorator{ + val path: String val methods: Seq[String] def subpath: Boolean = false - def wrapMethodOutput(ctx: ParamContext,t: R): cask.internal.Router.Result[Any] = cask.internal.Router.Result.Success(t) - def handle(ctx: ParamContext): Map[String, InputType] + def wrapMethodOutput(ctx: ParamContext,t: R): cask.internal.Router.Result[Any] = { + cask.internal.Router.Result.Success(t) + } + def getParamValues(ctx: ParamContext): Map[String, InputType] def wrapPathSegment(s: String): InputType + } - trait Decorator{ + trait BaseDecorator{ type InputType - def handle(ctx: ParamContext): Map[String, InputType] + type InputParser[T] + def getParamValues(ctx: ParamContext): Map[String, InputType] + def parseMethodInput[T](implicit p: InputParser[T]) = p + + } + + trait Decorator extends BaseDecorator { + type InputType = Any + type InputParser[T] = NoOpParser[InputType, T] + } + + class NoOpParser[InputType, T] extends ArgReader[InputType, T, ParamContext] { + def arity = 1 + + def read(ctx: ParamContext, label: String, input: InputType) = input.asInstanceOf[T] + } + object NoOpParser{ + implicit def instance[InputType, T] = new NoOpParser[InputType, T] } - case class EndpointMetadata[T](decorators: Seq[Decorator], + case class EndpointMetadata[T](decorators: Seq[BaseDecorator], endpoint: Endpoint[_], entryPoint: EntryPoint[T, ParamContext]) case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) @@ -35,7 +55,7 @@ object Routes{ val routeParts = for{ m <- c.weakTypeOf[T].members - val annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator]).reverse + val annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[BaseDecorator]).reverse if annotations.nonEmpty } yield { val annotObjects = diff --git a/cask/src/cask/package.scala b/cask/src/cask/package.scala index 791bc51..b791eb1 100644 --- a/cask/src/cask/package.scala +++ b/cask/src/cask/package.scala @@ -27,6 +27,7 @@ package object cask { // main type MainRoutes = main.MainRoutes type Routes = main.Routes + val Routes = main.Routes type Main = main.Main } diff --git a/cask/test/src/test/cask/Decorated.scala b/cask/test/src/test/cask/Decorated.scala new file mode 100644 index 0000000..94a1ce2 --- /dev/null +++ b/cask/test/src/test/cask/Decorated.scala @@ -0,0 +1,17 @@ +package test.cask +import cask.model.ParamContext + + +object Decorated extends cask.MainRoutes{ + class myDecorator extends cask.Routes.Decorator { + def getParamValues(ctx: ParamContext) = Map("extra" -> 31337) + } + + @myDecorator() + @cask.get("/hello/:world") + def hello(world: String)(extra: Int) = { + world + extra + } + + initialize() +} diff --git a/cask/test/src/test/cask/Decorator.scala b/cask/test/src/test/cask/Decorator.scala deleted file mode 100644 index e8927cf..0000000 --- a/cask/test/src/test/cask/Decorator.scala +++ /dev/null @@ -1,26 +0,0 @@ -package test.cask -import cask.internal.Router.ArgReader -import cask.model.ParamContext - - -object Decorator extends cask.MainRoutes{ - class myDecorator extends cask.main.Routes.Decorator { - type InputType = Int - - def handle(ctx: ParamContext) = Map("extra" -> 31337) - - def parseMethodInput[T] = new ArgReader[Int, T, ParamContext] { - def arity = 1 - - def read(ctx: ParamContext, label: String, input: Int) = input.asInstanceOf[T] - } - } - - @myDecorator() - @cask.get("/hello/:world") - def hello(world: String)(extra: Int) = { - world + extra - } - - initialize() -} diff --git a/cask/test/src/test/cask/ExampleTests.scala b/cask/test/src/test/cask/ExampleTests.scala index be0000c..50e9776 100644 --- a/cask/test/src/test/cask/ExampleTests.scala +++ b/cask/test/src/test/cask/ExampleTests.scala @@ -86,7 +86,7 @@ object ExampleTests extends TestSuite{ ).text() ==> "OK Plain(hello,null) List(1, 2)" } - 'Decorator - test(Decorator){ host => + 'Decorated - test(Decorated){ host => requests.get(host + "/hello/woo").text() ==> "woo31337" } -- cgit v1.2.3