forked from scalatra/scalatra
/
routeMatcher.scala
77 lines (62 loc) · 2.12 KB
/
routeMatcher.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package org.scalatra
import scala.util.matching.Regex
import util.MultiMap
trait RouteMatcher
{
def apply(): Option[ScalatraKernel.MultiParams]
}
trait ReversibleRouteMatcher
{
def reverse(params: Map[String, String], splats: List[String]): String
}
final class SinatraRouteMatcher(path: String, requestPath: => String)
extends RouteMatcher with ReversibleRouteMatcher
{
def apply() = SinatraPathPatternParser(path)(requestPath)
def reverse(params: Map[String, String], splats: List[String]): String = {
replaceSplats(
replaceNamedParams(
replaceOptionalParams(path, params),
params
), splats)
}
private def replaceOptionalParams(slug: String, params: Map[String, String]): String =
"""[\./]\?:[^/?#\.]+\?""".r replaceAllIn (path, s => {
params.get(s.matched slice (3, s.matched.size - 1)) match {
case Some(value) => s.matched.head + value
case None => ""
}
})
private def replaceNamedParams(slug: String, params: Map[String, String]): String =
""":[^/?#\.]+""".r replaceAllIn (slug, s =>
params.get(s.matched.tail) match {
case Some(value) => value
case None => throw new Exception("The url \"%s\" requires param \"%s\"" format (path, s))
})
private def replaceSplats(slug: String, splats: List[String]): String =
splats match {
case Nil => slug
case s :: rest => replaceSplats("""\*""".r replaceFirstIn (slug, s), rest)
}
override def toString = path
}
final class PathPatternRouteMatcher(pattern: PathPattern, requestPath: => String)
extends RouteMatcher
{
def apply() = pattern(requestPath)
override def toString = pattern.regex.toString
}
final class RegexRouteMatcher(regex: Regex, requestPath: => String)
extends RouteMatcher
{
def apply() = regex.findFirstMatchIn(requestPath) map { _.subgroups match {
case Nil => MultiMap()
case xs => Map("captures" -> xs)
}}
override def toString = regex.toString
}
final class BooleanBlockRouteMatcher(block: => Boolean) extends RouteMatcher
{
def apply() = if (block) Some(MultiMap()) else None
override def toString = "[Boolean Guard]"
}