-
Notifications
You must be signed in to change notification settings - Fork 0
/
Routes.scala
81 lines (63 loc) · 2.48 KB
/
Routes.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
78
79
80
81
package tel.fiftythree
import tel.fiftythree.Tuples.Composition
import scala.language.higherKinds
import scala.util.matching.Regex
object Routes {
trait DSL[Router[_]] {
/** Matches an exact string */
def literal(repr: String): Router[Unit] =
core.map[String, Unit](_ => (), _ => repr)(regex(repr.r))
/** Matches any string that passes a regex filter */
def regex(pattern: Regex): Router[String]
/**
* Convenient interface for `represented` where we use an implicit
* `Representation` value. Same as `represented[A](implicitly)`.
*/
def some[A: Representation]: Router[A] = represented(implicitly)
/**
* Provided a `Representation` of some type as a String, we check to see
* if the next segment of the path matches.
*/
def represented[A](repr: Representation[A]): Router[A]
/** Matches any non-empty string */
def string: Router[String] = some
/** Core semantic combinators */
val core: Core[Router]
implicit class DslInfixOperations[A](ra: Router[A]) {
def ~[B](rb: Router[B])(implicit c: Composition[A, B]) =
core.pairFlat(ra, rb)(c)
}
}
/**
* Core exterior properties of a Router.
*
* The primary namespace to use is `DSL`. These are separated out (though
* still available) since they form the basis of operation but don't help
* with the presentation of the DSL.
*/
trait Core[Router[_]] {
/**
* Given a transform and its inverse (really, retraction) we can transform
* a Router producing one type to a different router.
*/
def map[A, B](f: A => B, g: B => A)(r: Router[A]): Router[B]
/**
* Inject a value into a router without examining or consuming the
* location.
*/
def unit[A](a: A): Router[A]
/**
* Execute two parses sequentially and return both results. Unlike
* `pair`, `pairFlat` uses an implicit `Composition` to try to smash
* tuples together "flatly".
*/
def pairFlat[A, B](ra: Router[A], rb: Router[B])(implicit c: Composition[A, B]): Router[c.C] =
map[(A, B), c.C](x => c.smash(x._1, x._2), x => (c._1(x), c._2(x)))(pair(ra, rb))
/**
* Execute two parses sequentially and return both results as a tuple.
* Unlike `pairFlat` this does not do any extra work to try to flatten
* tuples. Can be considered a type-specialized version of `pairFlat`.
*/
def pair[A, B](ra: Router[A], rb: Router[B]): Router[(A, B)] = pairFlat(ra, rb)
}
}