Browse Source

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.
Carl Jackson 12 years ago
parent
commit
e16aa3c10c
4 changed files with 33 additions and 12 deletions
  1. +15
    -3
      web/pattern.go
  2. +2
    -1
      web/pattern_test.go
  3. +10
    -6
      web/router.go
  4. +6
    -2
      web/router_test.go

+ 15
- 3
web/pattern.go View File

@ -19,7 +19,14 @@ type regexpPattern struct {
func (p regexpPattern) Prefix() string { func (p regexpPattern) Prefix() string {
return p.prefix 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) matches := p.re.FindStringSubmatch(r.URL.Path)
if matches == nil || len(matches) == 0 { if matches == nil || len(matches) == 0 {
return false return false
@ -148,8 +155,13 @@ type stringPattern struct {
func (s stringPattern) Prefix() string { func (s stringPattern) Prefix() string {
return s.literals[0] 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 path := r.URL.Path
var matches map[string]string var matches map[string]string
if !dryrun && len(s.pats) > 0 { if !dryrun && len(s.pats) > 0 {


+ 2
- 1
web/pattern_test.go View File

@ -162,12 +162,13 @@ func TestPatterns(t *testing.T) {
} }
func runTest(t *testing.T, p Pattern, test patternTest) { 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 { if result != test.match {
t.Errorf("Expected match(%v, %#v) to return %v", p, t.Errorf("Expected match(%v, %#v) to return %v", p,
test.r.URL.Path, test.match) test.r.URL.Path, test.match)
return return
} }
p.Run(test.r, test.c)
if !reflect.DeepEqual(test.c, test.cout) { if !reflect.DeepEqual(test.c, test.cout) {
t.Errorf("Expected a context of %v, instead got %v", test.cout, t.Errorf("Expected a context of %v, instead got %v", test.cout,


+ 10
- 6
web/router.go View File

@ -78,10 +78,13 @@ type Pattern interface {
Prefix() string Prefix() string
// Returns true if the request satisfies the pattern. This function is // Returns true if the request satisfies the pattern. This function is
// free to examine both the request and the context to make this // 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 { 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 { 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 return false
} }
*ms |= route.method *ms |= route.method
if route.method&m != 0 { if route.method&m != 0 {
return route.pattern.Match(r, c, false)
route.pattern.Run(r, c)
return true
} }
return false return false
} }


+ 6
- 2
web/router_test.go View File

@ -64,9 +64,11 @@ func (t testPattern) Prefix() string {
return "" 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 return true
} }
func (t testPattern) Run(r *http.Request, c *C) {
}
var _ Pattern = testPattern{} var _ Pattern = testPattern{}
@ -174,9 +176,11 @@ type rsPattern struct {
func (rs rsPattern) Prefix() string { func (rs rsPattern) Prefix() string {
return rs.prefix 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 return rs.i >= *rs.counter
} }
func (rs rsPattern) Run(_ *http.Request, _ *C) {
}
func (rs rsPattern) ServeHTTP(_ http.ResponseWriter, _ *http.Request) { func (rs rsPattern) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {
rs.ichan <- rs.i rs.ichan <- rs.i


Loading…
Cancel
Save