-
-
Save dann/254959 to your computer and use it in GitHub Desktop.
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 com.thinkminimo.step | |
| import javax.servlet._ | |
| import javax.servlet.http._ | |
| import scala.util.DynamicVariable | |
| import scala.util.matching.Regex | |
| import scala.collection.mutable.HashSet | |
| import scala.collection.jcl.MapWrapper | |
| object Step | |
| { | |
| type Params = Map[String, String] | |
| type Action = Any => String | |
| // immutableな変数 | |
| val protocols = List("GET", "POST", "PUT", "DELETE") | |
| } | |
| import Step._ | |
| abstract class Step extends HttpServlet | |
| { | |
| // protcolsをmapしてる。 | |
| // Mapの _*はrubyで配列を展開して渡したりするときにやるのと同じ hoge( *array ) | |
| val Routes = Map(protocols map (_ -> new HashSet[Route]): _*) | |
| // DynamicVariableはperlのlocal変数的なもの | |
| //class DynamicVariable[A] | |
| //{ | |
| // private val tl = new ThreadLocal | |
| // def get : A = tl.get().asInstanceOf[A] | |
| // def withValue[B](x : A)(f : => B) : B = { | |
| // val old = get | |
| // try { | |
| // tl.set(x) | |
| // f | |
| // } finally { | |
| // tl.set(old) | |
| // } | |
| // } | |
| //} | |
| val paramsMap = new DynamicVariable[Params](null) | |
| var contentType = "text/html" | |
| class Route(val path: String, val action: Action) { | |
| val pattern = """:\w+""" | |
| val names = new Regex(pattern) findAllIn path toList | |
| val re = new Regex("^%s$" format path.replaceAll(pattern, "(.*?)")) | |
| // Mapの _*はrubyで配列を展開して渡したりするときにやるのと同じ hoge( *array ) | |
| def apply(realPath: String): Option[Params] = | |
| re findFirstMatchIn realPath map (x => Map(names zip x.subgroups : _*)) | |
| override def toString():String = path | |
| } | |
| override def service(request: HttpServletRequest, response: HttpServletResponse) { | |
| val realParams = new MapWrapper[String, Array[String]]() { | |
| def underlying = request.getParameterMap.asInstanceOf[java.util.Map[String,Array[String]]] | |
| }.map { case (k,v) => (k, v(0)) } | |
| //local関数 | |
| def isMatchingRoute(route: Route) = { | |
| def exec(args: Params) = { | |
| // _は何? | |
| before _ | |
| // method callしてるだけ。.がなくていい | |
| response setContentType contentType | |
| // ++はコレクションの合体 | |
| //DynamicVariable クラスの withValue メソッドはある値とブロックをとり、 | |
| //渡された値で動的変数の内容を一時的に改変してブロックを実行します。 | |
| // ブロックの実行が終わると動的変数の値は元に戻る。 | |
| paramsMap.withValue(args ++ realParams) { | |
| // actionはAny => Stringの関数なので、それを実行してる。 | |
| response.getWriter print route.action() | |
| } | |
| } | |
| //getPathInfo returns everything after the context path, so step will work if non-root | |
| route(request.getPathInfo) map exec isDefined | |
| } | |
| if (Routes(request.getMethod) find isMatchingRoute isEmpty) | |
| response.getWriter println "Requesting %s but only have %s".format(request.getRequestURI, Routes) | |
| } | |
| def params(name: String): String = paramsMap value name | |
| def before(fun: => Any) = fun | |
| // dispatch tableつくってるのはここ。 | |
| // get("/x") blockをdispatch tableにつっこんでいるのはここ | |
| // Routesにつっこんでって、mapした結果が最終的にListになってるってことを保証するためだけにListが使われている。 | |
| val List(get, post, put, delete) = protocols map routeSetter | |
| // functional programming means never having to repeat yourself | |
| // (=> Anyは何の略?) | |
| // (String) => (=> Any) => Unit | |
| // (String) => (()=> Any)) => Unit | |
| // Stringをいれると、 (() =>Any) => Unitな関数を返す関数? | |
| // x => fun.toStringの部分は、 xをいれると、fun.toStringを返す関数 | |
| private def routeSetter(protocol: String): (String) => (=> Any) => Unit = { | |
| // fun.toStringは、fun().toString()している | |
| // fun: => Anyは、 fun: () => Any の省略形。引数がない場合は省略できる。 | |
| // funは、() => Anyにする関数 | |
| def g(path: String, fun: => Any) = Routes(protocol) += new Route(path, x => fun.toString) | |
| // (g _)部分 | |
| // functionName _ とすると | |
| // 明示的に参照として扱える(?) | |
| // var ref = function(hoge) { functionName(hoge); } | |
| // の参照 | |
| // curryはまさにcurry化 | |
| // (String, String) => Stringみたいな型の関数を | |
| // (String) => (String) => Stringみたいに | |
| (g _).curry | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment