3 // Copyright 2013 Ernest Micklei. All rights reserved.
4 // Use of this source code is governed by a license
5 // that can be found in the LICENSE file.
14 // PathExpression holds a compiled path expression (RegExp) needed to match against
15 // Http request paths and to extract path parameter values.
16 type pathExpression struct {
17 LiteralCount int // the number of literal characters (means those not resulting from template variable substitution)
18 VarNames []string // the names of parameters (enclosed by {}) in the path
19 VarCount int // the number of named parameters (enclosed by {}) in the path
20 Matcher *regexp.Regexp
21 Source string // Path as defined by the RouteBuilder
25 // NewPathExpression creates a PathExpression from the input URL path.
26 // Returns an error if the path is invalid.
27 func newPathExpression(path string) (*pathExpression, error) {
28 expression, literalCount, varNames, varCount, tokens := templateToRegularExpression(path)
29 compiled, err := regexp.Compile(expression)
33 return &pathExpression{literalCount, varNames, varCount, compiled, expression, tokens}, nil
36 // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-370003.7.3
37 func templateToRegularExpression(template string) (expression string, literalCount int, varNames []string, varCount int, tokens []string) {
38 var buffer bytes.Buffer
39 buffer.WriteString("^")
40 //tokens = strings.Split(template, "/")
41 tokens = tokenizePath(template)
42 for _, each := range tokens {
46 buffer.WriteString("/")
47 if strings.HasPrefix(each, "{") {
48 // check for regular expression in variable
49 colon := strings.Index(each, ":")
53 varName = strings.TrimSpace(each[1:colon])
54 paramExpr := strings.TrimSpace(each[colon+1 : len(each)-1])
55 if paramExpr == "*" { // special case
56 buffer.WriteString("(.*)")
58 buffer.WriteString(fmt.Sprintf("(%s)", paramExpr)) // between colon and closing moustache
62 varName = strings.TrimSpace(each[1 : len(each)-1])
63 buffer.WriteString("([^/]+?)")
65 varNames = append(varNames, varName)
68 literalCount += len(each)
69 encoded := each // TODO URI encode
70 buffer.WriteString(regexp.QuoteMeta(encoded))
73 return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varNames, varCount, tokens