From e16aa3c10c36f67ad5f1f1796fcdfe0bfd8da25e Mon Sep 17 00:00:00 2001 From: Carl Jackson Date: Sun, 4 May 2014 17:25:23 -0700 Subject: [PATCH] Split Pattern.Match in two; get rid of dryrun The "dryrun" parameter on Pattern.Match was kind of ugly and made for an exceedingly mediocre public interface. Instead, split its functionality in two: the previous "dryrun" behavior now lives in the Match method, and Patterns now actually mutate state when Run is called. The code on the backend is of course still the same (for now), but at least the interface is a little nicer. --- web/pattern.go | 18 +++++++++++++++--- web/pattern_test.go | 3 ++- web/router.go | 16 ++++++++++------ web/router_test.go | 8 ++++++-- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/web/pattern.go b/web/pattern.go index 69f5654..903f6fd 100644 --- a/web/pattern.go +++ b/web/pattern.go @@ -19,7 +19,14 @@ type regexpPattern struct { func (p regexpPattern) Prefix() string { return p.prefix } -func (p regexpPattern) Match(r *http.Request, c *C, dryrun bool) bool { +func (p regexpPattern) Match(r *http.Request, c *C) bool { + return p.match(r, c, false) +} +func (p regexpPattern) Run(r *http.Request, c *C) { + p.match(r, c, false) +} + +func (p regexpPattern) match(r *http.Request, c *C, dryrun bool) bool { matches := p.re.FindStringSubmatch(r.URL.Path) if matches == nil || len(matches) == 0 { return false @@ -148,8 +155,13 @@ type stringPattern struct { func (s stringPattern) Prefix() string { return s.literals[0] } - -func (s stringPattern) Match(r *http.Request, c *C, dryrun bool) bool { +func (s stringPattern) Match(r *http.Request, c *C) bool { + return s.match(r, c, true) +} +func (s stringPattern) Run(r *http.Request, c *C) { + s.match(r, c, false) +} +func (s stringPattern) match(r *http.Request, c *C, dryrun bool) bool { path := r.URL.Path var matches map[string]string if !dryrun && len(s.pats) > 0 { diff --git a/web/pattern_test.go b/web/pattern_test.go index 2ea3c90..6b2575f 100644 --- a/web/pattern_test.go +++ b/web/pattern_test.go @@ -162,12 +162,13 @@ func TestPatterns(t *testing.T) { } func runTest(t *testing.T, p Pattern, test patternTest) { - result := p.Match(test.r, test.c, false) + result := p.Match(test.r, test.c) if result != test.match { t.Errorf("Expected match(%v, %#v) to return %v", p, test.r.URL.Path, test.match) return } + p.Run(test.r, test.c) if !reflect.DeepEqual(test.c, test.cout) { t.Errorf("Expected a context of %v, instead got %v", test.cout, diff --git a/web/router.go b/web/router.go index e5ed9dd..5c3c041 100644 --- a/web/router.go +++ b/web/router.go @@ -78,10 +78,13 @@ type Pattern interface { Prefix() string // Returns true if the request satisfies the pattern. This function is // free to examine both the request and the context to make this - // decision. After it is certain that the request matches, this function - // should mutate or create c.URLParams if necessary, unless dryrun is - // set. - Match(r *http.Request, c *C, dryrun bool) bool + // decision. Match should not modify either argument, and since it will + // potentially be called several times over the course of matching a + // request, it should be reasonably efficient. + Match(r *http.Request, c *C) bool + // Run the pattern on the request and context, modifying the context as + // necessary to bind URL parameters or other parsed state. + Run(r *http.Request, c *C) } func parsePattern(p interface{}) Pattern { @@ -144,13 +147,14 @@ type routeMachine struct { } func matchRoute(route route, m method, ms *method, r *http.Request, c *C) bool { - if !route.pattern.Match(r, c, true) { + if !route.pattern.Match(r, c) { return false } *ms |= route.method if route.method&m != 0 { - return route.pattern.Match(r, c, false) + route.pattern.Run(r, c) + return true } return false } diff --git a/web/router_test.go b/web/router_test.go index 442903e..59955cb 100644 --- a/web/router_test.go +++ b/web/router_test.go @@ -64,9 +64,11 @@ func (t testPattern) Prefix() string { return "" } -func (t testPattern) Match(r *http.Request, c *C, dryrun bool) bool { +func (t testPattern) Match(r *http.Request, c *C) bool { return true } +func (t testPattern) Run(r *http.Request, c *C) { +} var _ Pattern = testPattern{} @@ -174,9 +176,11 @@ type rsPattern struct { func (rs rsPattern) Prefix() string { return rs.prefix } -func (rs rsPattern) Match(_ *http.Request, _ *C, _ bool) bool { +func (rs rsPattern) Match(_ *http.Request, _ *C) bool { return rs.i >= *rs.counter } +func (rs rsPattern) Run(_ *http.Request, _ *C) { +} func (rs rsPattern) ServeHTTP(_ http.ResponseWriter, _ *http.Request) { rs.ichan <- rs.i