summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-02-15 11:53:40 -0600
committerJesse Luehrs <doy@tozt.net>2013-02-15 11:53:40 -0600
commitd365b7e335534a2161ce429220f1bc98e973c83b (patch)
tree3a9f0c0c1e9fe545f2a3f14d2f81a00899ac0808
parentac2fbb56010e3d82512f815e1cd38a20b8f79dc3 (diff)
downloadscala-path-router-d365b7e335534a2161ce429220f1bc98e973c83b.tar.gz
scala-path-router-d365b7e335534a2161ce429220f1bc98e973c83b.zip
no reason routes themselves should be public
-rw-r--r--src/main/scala/router.scala206
-rw-r--r--src/test/scala/basic.scala6
2 files changed, 103 insertions, 109 deletions
diff --git a/src/main/scala/router.scala b/src/main/scala/router.scala
index 9df7a2a..5779256 100644
--- a/src/main/scala/router.scala
+++ b/src/main/scala/router.scala
@@ -4,8 +4,6 @@ import scala.collection.mutable.ArrayBuffer
import scala.util.matching.Regex
class Router[T] {
- val routes = new ArrayBuffer[Route[T]]()
-
def addRoute (
path: String,
target: T,
@@ -31,7 +29,7 @@ class Router[T] {
def route (path: String): Option[Match[T]] = {
def testRoutes (
components: Seq[String],
- routes: List[Route[T]]
+ routes: List[Route]
): Option[Match[T]] = routes match {
case r :: rs => r.route(components) match {
case Some(found) => Some(found)
@@ -42,18 +40,6 @@ class Router[T] {
testRoutes(path.split("/"), routes.toList)
}
- 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
@@ -89,118 +75,132 @@ class Router[T] {
}
}
}
-}
-class Route[T] (
- val path: String,
- val defaults: Map[String, String],
- val validations: Map[String, Regex],
- val target: T
-) {
- import Route._
-
- lazy val variables = components.flatMap(getVariableName)
-
- def route(
- parts: Seq[String],
- components: Seq[String] = components,
- mapping: Map[String, String] = defaults
- ): Option[Match[T]] = {
- if (components.filter(!isOptional(_)).length == 0 && parts.length == 0) {
- Some(new Match[T](path, mapping, target))
- }
- else if (components.length == 0 || parts.length == 0) {
- None
- }
- else {
- components.head match {
- case Optional(name) => {
- if (validate(name, parts.head)) {
- route(parts.tail, components.tail, mapping + (name -> parts.head))
- }
- else {
- route(parts, components.tail, mapping)
+ private val routes = new ArrayBuffer[Route]()
+
+ private class Route (
+ val path: String,
+ val defaults: Map[String, String],
+ val validations: Map[String, Regex],
+ val target: T
+ ) {
+ import Route._
+
+ lazy val variables = components.flatMap(getVariableName)
+
+ def route(
+ parts: Seq[String],
+ components: Seq[String] = components,
+ mapping: Map[String, String] = defaults
+ ): Option[Match[T]] = {
+ if (components.filter(!isOptional(_)).length == 0 && parts.length == 0) {
+ Some(new Match[T](path, mapping, target))
+ }
+ else if (components.length == 0 || parts.length == 0) {
+ None
+ }
+ else {
+ components.head match {
+ case Optional(name) => {
+ if (validate(name, parts.head)) {
+ route(parts.tail, components.tail, mapping + (name -> parts.head))
+ }
+ else {
+ route(parts, components.tail, mapping)
+ }
}
- }
- case Variable(name) => {
- if (validate(name, parts.head)) {
- route(parts.tail, components.tail, mapping + (name -> parts.head))
+ case Variable(name) => {
+ if (validate(name, parts.head)) {
+ route(parts.tail, components.tail, mapping + (name -> parts.head))
+ }
+ else {
+ None
+ }
}
- else {
- None
+ case literal => parts.head match {
+ case `literal` => route(parts.tail, components.tail, mapping)
+ case _ => None
}
}
- case literal => parts.head match {
- case `literal` => route(parts.tail, components.tail, mapping)
- case _ => None
- }
}
}
- }
- override def toString = path
+ override def toString = path
- def pathWithMapping (mapping: Map[String, String]): Option[String] = {
- val requiredDefaults = defaults.keys.filter { k =>
- mapping.isDefinedAt(k) && !variables.contains(k)
- }
- if (requiredDefaults.forall(k => defaults(k) == mapping(k)) &&
- requiredVariables.forall(mapping.isDefinedAt)) {
- val boundComponents = components.flatMap {
- case Optional(v) => {
- val component = (mapping get v).flatMap(validComponentValue(v, _))
- defaults get v match {
- case Some(default) => {
- component.flatMap {
- case `default` => None
- case c => Some(c)
+ def pathWithMapping (mapping: Map[String, String]): Option[String] = {
+ val requiredDefaults = defaults.keys.filter { k =>
+ mapping.isDefinedAt(k) && !variables.contains(k)
+ }
+ if (requiredDefaults.forall(k => defaults(k) == mapping(k)) &&
+ requiredVariables.forall(mapping.isDefinedAt)) {
+ val boundComponents = components.flatMap {
+ case Optional(v) => {
+ val component = (mapping get v).flatMap(validComponentValue(v, _))
+ defaults get v match {
+ case Some(default) => {
+ component.flatMap {
+ case `default` => None
+ case c => Some(c)
+ }
}
+ case None => component
}
- case None => component
}
+ case Variable(v) => validComponentValue(v, (mapping(v)))
+ case literal => Some(literal)
}
- case Variable(v) => validComponentValue(v, (mapping(v)))
- case literal => Some(literal)
+ Some(boundComponents.mkString("/"))
+ }
+ else {
+ None
}
- Some(boundComponents.mkString("/"))
- }
- else {
- None
}
- }
-
- private lazy val components =
- path.split("/").filter(_.length > 0)
- private lazy val requiredVariables =
- components.filter(!isOptional(_)).flatMap(getVariableName)
+ private lazy val components =
+ path.split("/").filter(_.length > 0)
- private lazy val hasVariable = variables.toSet
+ private lazy val requiredVariables =
+ components.filter(!isOptional(_)).flatMap(getVariableName)
- private def isOptional (component: String) =
- Optional.findFirstIn(component).nonEmpty
+ private lazy val hasVariable = variables.toSet
- private def isVariable (component: String) =
- Variable.findFirstIn(component).nonEmpty
+ private def isOptional (component: String) =
+ Optional.findFirstIn(component).nonEmpty
- private def getVariableName (component: String) = component match {
- case Variable(name) => Some(name)
- case _ => None
- }
+ private def isVariable (component: String) =
+ Variable.findFirstIn(component).nonEmpty
- private def validate (name: String, component: String) =
- validations get name match {
- case Some(rx) => rx.findFirstIn(component).nonEmpty
- case None => true
+ private def getVariableName (component: String) = component match {
+ case Variable(name) => Some(name)
+ case _ => None
}
- private def validComponentValue (name: String, component: String) =
- if (validate(name, component)) { Some(component) } else { None }
-}
+ private def validate (name: String, component: String) =
+ validations get name match {
+ case Some(rx) => rx.findFirstIn(component).nonEmpty
+ case None => true
+ }
+
+ private def validComponentValue (name: String, component: String) =
+ if (validate(name, component)) { Some(component) } else { None }
+ }
-object Route {
- private val Optional = """^\?:(.*)$""".r
- private val Variable = """^\??:(.*)$""".r
+ private object Route {
+ private val Optional = """^\?:(.*)$""".r
+ private val Variable = """^\??:(.*)$""".r
+ }
+
+ 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(", ")
+ }
+ }
}
class Match[T] (
diff --git a/src/test/scala/basic.scala b/src/test/scala/basic.scala
index 686a313..71aa370 100644
--- a/src/test/scala/basic.scala
+++ b/src/test/scala/basic.scala
@@ -65,12 +65,6 @@ class Basic extends FunSuite {
assert(m.target === true)
}
- test ("routes are created in the correct order") {
- assert(router.routes(0).path === "blog")
- assert(router.routes(2).path === "blog/:action/:id")
- assert(router.routes(3).path === "test/?:x/?:y")
- }
-
test ("routes match properly") {
testRoute(
router, "blog", Map(