diff options
author | Jesse Luehrs <doy@tozt.net> | 2013-02-14 17:39:46 -0600 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2013-02-14 17:44:28 -0600 |
commit | 6af0bb7aa231c41213b455e1ae44a50a5b295292 (patch) | |
tree | 4549593b7599ae37c1e336bfc60819159fe395be /src/main/scala | |
parent | 84000c335f5cdd2bb3994e7062f30836f2275b4d (diff) | |
download | scala-path-router-6af0bb7aa231c41213b455e1ae44a50a5b295292.tar.gz scala-path-router-6af0bb7aa231c41213b455e1ae44a50a5b295292.zip |
implement uriFor
Diffstat (limited to 'src/main/scala')
-rw-r--r-- | src/main/scala/router.scala | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/src/main/scala/router.scala b/src/main/scala/router.scala index a9b2ec1..56e0342 100644 --- a/src/main/scala/router.scala +++ b/src/main/scala/router.scala @@ -42,8 +42,55 @@ class Router[T] { _route(path.split("/"), routes.toList) } - def uriFor (mapping: Map[String, String]): String = { - throw new Error("unimplemented") + private class AmbiguousRouteMapping( + mapping: Map[String, String], + paths: Seq[String] + ) extends RuntimeException { + override def getMessage (): String = { + "Ambiguous path descriptor (specified keys " + + mapping.keys.mkString(", ") + + "): could match paths " + + paths.mkString(", ") + } + } + + def uriFor (mapping: Map[String, String]): Option[String] = { + // first remove all routes that can't possibly match + // - if the route requires a variable component that doesn't exist in the + // mapping, then it can't match + // - if the route contains a value for a variable component that doesn't + // pass the validation for that component, it can't match + // - if the route contains a default value, and that component also exists + // in the mapping, then the values must match + val possible = routes.flatMap(r => { + r.pathWithMapping(mapping) match { + case Some(path) => Some(r -> path) + case None => None + } + }) + + possible.toList match { + case Nil => None + case (r, path) :: Nil => Some(path) + case rs => { + // then try to disambiguate the remaining possibilities + // - we want the route with the fewest number of "extra" items in the + // mapping, after removing defaults and variable path components + val possibleByRemainder = possible.groupBy { case (r, path) => { + (mapping.keys.toSet -- + r.defaults.keys.toSet -- + r.requiredVariableComponents -- + r.optionalVariableComponents).size + } } + val found = possibleByRemainder(possibleByRemainder.keys.min) + found.toList match { + case Nil => None + case (r, path) :: Nil => Some(path) + case rs => + throw new AmbiguousRouteMapping(mapping, rs.map(_._1.path)) + } + } + } } } |