diff options
author | Franck Cuny <franck@lumberjaph.net> | 2013-04-21 11:38:48 -0700 |
---|---|---|
committer | Franck Cuny <franck@lumberjaph.net> | 2013-04-21 11:38:48 -0700 |
commit | 67e3e5b2bf87bc77de70063347337c4787f0df48 (patch) | |
tree | a5b9a8be9c15f1aa62b430b27132f2a8ef75ff9e | |
parent | Add very simple test to validate routes. (diff) | |
download | path-router-67e3e5b2bf87bc77de70063347337c4787f0df48.tar.gz |
Add support for optional parameter in a path.
If a component in the path starts with "?:", it means that it's optional. We then store the lenght of the components without those optional parameters.
-rw-r--r-- | route.go | 24 | ||||
-rw-r--r-- | router_test.go | 26 |
2 files changed, 43 insertions, 7 deletions
diff --git a/route.go b/route.go index 1950307..d84d026 100644 --- a/route.go +++ b/route.go @@ -14,6 +14,7 @@ type Route struct { RequiredNamedComponents map[string]bool OptionalNamedComponents map[string]bool Length int + LengthWithoutOptional int } type Match struct { @@ -24,6 +25,7 @@ type Match struct { } var componentIsVariable = regexp.MustCompile("^:") +var componentsIsOptional = regexp.MustCompile("^?:") var namedComponentsRegex = regexp.MustCompile("^:(.*)$") func (self *Route) Match(request Request) *Match { @@ -40,13 +42,16 @@ func (self *Route) Match(request Request) *Match { components := strings.Split(request.Request.URL.Path, "/") - if len(components) < self.Length { + if len(components) < self.LengthWithoutOptional || len(components) > self.Length { return nil } mapping := map[string]string{} for i, c := range self.Components { + if componentsIsOptional.MatchString(c) { + break + } p := components[i] if componentIsVariable.MatchString(c) == true { @@ -83,26 +88,31 @@ func MakeRoute(path string, method string, code func(*Request) (Response, error) } } - namedComponents := getNamedComponents(components) + reqComponents, optComponents := getNamedComponents(components) exec := fn{method: code} route := Route{ Path: path, Executors: exec, Components: components, - RequiredNamedComponents: namedComponents, + RequiredNamedComponents: reqComponents, + OptionalNamedComponents: optComponents, Length: len(components), + LengthWithoutOptional: len(components) - len(optComponents), } return route } -func getNamedComponents(components []string) map[string]bool { - namedComponents := map[string]bool{} +func getNamedComponents(components []string) (map[string]bool, map[string]bool) { + reqComponents := map[string]bool{} + optComponents := map[string]bool{} for _, c := range components { if namedComponentsRegex.MatchString(c) == true { - namedComponents[c] = true + reqComponents[c] = true + } else if componentsIsOptional.MatchString(c) == true { + optComponents[c] = true } } - return namedComponents + return reqComponents, optComponents } diff --git a/router_test.go b/router_test.go index 5b85aa8..28895b9 100644 --- a/router_test.go +++ b/router_test.go @@ -4,6 +4,7 @@ import ( "net/http" "net/url" "testing" + "fmt" ) func testRoute(req *Request) (Response, error) { @@ -41,6 +42,31 @@ func TestMatch(t *testing.T) { m := router.Match(req) if m == nil { t.Fatal() + }else{ + fmt.Println(fmt.Sprintf("%s match for %s", p.Path, m.Path)) + } + } +} + +func TestMatchOptional(t *testing.T) { + router := BuildDispatcher() + router.AddRoute("/blog/?:year", "GET", testRoute) + router.AddRoute("/blog/:year/?:month", "GET", testRoute) + + pathToTests := []url.URL{ + url.URL{Path: "blog"}, + url.URL{Path: "/blog"}, + url.URL{Path: "blog/2013"}, + url.URL{Path: "/blog/2013/21"}, + } + for _, p := range pathToTests { + r := http.Request{URL: &p, Method: "GET"} + req := Request{&r} + m := router.Match(req) + if m == nil { + t.Fatal() + }else{ + fmt.Println(fmt.Sprintf("%s match for %s", p.Path, m.Path)) } } } |