<commit_before>// Some utility functions to be refactored into their own packages.
//
// We want an api like:
// var router := NewRouter()
// router.Get("path", handler)
// router.Post("path", handler)
// router.Put("path", handler)
// router.Delete("path", handler)
//
// Once a user tries to register a path/handler we do
//   - analyse the path
package router

import (
	"net/http"
	"regexp"
	"strings"
)

// Stores
// ----------------------

// Store to keep track of the request parameters
var paramsStore = make(map[*http.Request]map[string]string)

// Router
// ----------------------

// A Router to register paths and requesthandlers to.
// There should be only one per application.
type Router struct {
	routes map[string][]*requestHandler
}

// NewRouter creates a router and returns a pointer to it so
// you can start registering routes.
//
// Dont forget to call `router.Handle(pattern)` to actually use
// the router.
func NewRouter() (router *Router) {
	router = new(Router)

	router.routes = map[string][]*requestHandler{
		"GET":    make([]*requestHandler, 0),
		"POST":   make([]*requestHandler, 0),
		"PUT":    make([]*requestHandler, 0),
		"DELETE": make([]*requestHandler, 0),
	}
	return
}

// Register a GET path to be handled.
func (router *Router) Get(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("GET", path, handler)
}

// Register a POST path to be handled.
func (router *Router) Post(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("POST", path, handler)
}

// Register a PUT path to be handled.
func (router *Router) Put(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("PUT", path, handler)
}

// Register a DELETE path to be handled.
func (router *Router) Delete(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("DELETE", path, handler)
}

// Handle registers the router for the given pattern in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
//
// This just delegetes to `http.Handle()` internally.
//
// Most of the times, you just want to do `router.Handle("/")`.
func (router *Router) Handle(pattern string) {
	http.Handle(pattern, router)
}

// Needed by go to actually start handling the registered routes.
// You don't need to call this yourself.
func (router *Router) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	// For each of the registered routes for this request method...
	for _, reqHandler := range router.routes[req.Method] {
		// Only when the route matches...
		if isAMatch, withParams := reqHandler.matches(req.URL.Path); isAMatch {
			// Capture the route params
			paramsStore[req] = withParams
			// Fire the handler
			reqHandler.Handler(res, req)
			// Clean up
			delete(paramsStore, req)
			break
		}
	}
}

// Helper function to actually register the requestHandler on the router
func (router *Router) registerRequestHandler(method string, path string, handler http.HandlerFunc) {
	reqHandler := makeRequestHandler(path, handler)
	router.routes[method] = append(router.routes[method], reqHandler)
}

// Exported helper funcs
// ---------------------------

// Access the request parameters for a given request
func Params(req *http.Request) (reqParams map[string]string, ok bool) {
	reqParams, ok = paramsStore[req]
	return
}

// Private helper funcs
// ---------------------------

// Some paths use tokens like "/user/:userid" where "userid" is the token.
//
// This function builds a string to be compiled as a regexp to match those
// paths and returns the names of the parameters found in the route.
func buildRegexpFor(path string) (regexpPath string, withParamNames []string) {
	parts := strings.Split(path, "/")
	items := make([]string, 0)<commit_msg>Allow to set a custom NotFoundHandler.<commit_after>// Some utility functions to be refactored into their own packages.
//
// We want an api like:
// var router := NewRouter()
// router.Get("path", handler)
// router.Post("path", handler)
// router.Put("path", handler)
// router.Delete("path", handler)
//
// Once a user tries to register a path/handler we do
//   - analyse the path
package router

import (
	"net/http"
	"regexp"
	"strings"
)

// Stores
// ----------------------

// Store to keep track of the request parameters
var paramsStore = make(map[*http.Request]map[string]string)

// Router
// ----------------------

// A Router to register paths and requestHandlers to.
//
// Set a custom NotFoundHandler if you want to override go's default one.
//
// There can be multiple per application, if so, don't forget to pass a
// different pattern to `router.Handle()`.
type Router struct {
	routes map[string][]*requestHandler
	// Specify a custom NotFoundHandler
	NotFoundHandler http.HandlerFunc
}

// NewRouter creates a router and returns a pointer to it so
// you can start registering routes.
//
// Dont forget to call `router.Handle(pattern)` to actually use
// the router.
func NewRouter() (router *Router) {
	router = new(Router)

	router.routes = map[string][]*requestHandler{
		"GET":    make([]*requestHandler, 0),
		"POST":   make([]*requestHandler, 0),
		"PUT":    make([]*requestHandler, 0),
		"DELETE": make([]*requestHandler, 0),
	}
	return
}

// Register a GET path to be handled.
func (router *Router) Get(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("GET", path, handler)
}

// Register a POST path to be handled.
func (router *Router) Post(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("POST", path, handler)
}

// Register a PUT path to be handled.
func (router *Router) Put(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("PUT", path, handler)
}

// Register a DELETE path to be handled.
func (router *Router) Delete(path string, handler http.HandlerFunc) {
	router.registerRequestHandler("DELETE", path, handler)
}

// Handle registers the router for the given pattern in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
//
// This just delegetes to `http.Handle()` internally.
//
// Most of the times, you just want to do `router.Handle("/")`.
func (router *Router) Handle(pattern string) {
	http.Handle(pattern, router)
}

// Needed by go to actually start handling the registered routes.
// You don't need to call this yourself.
func (router *Router) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	unMatched := true

	// For each of the registered routes for this request method...
	for _, reqHandler := range router.routes[req.Method] {
		// Only when the route matches...
		if isAMatch, withParams := reqHandler.matches(req.URL.Path); isAMatch {
			unMatched = false

			// Capture the route params
			paramsStore[req] = withParams
			// Fire the handler
			reqHandler.Handler(res, req)
			// Clean up
			delete(paramsStore, req)
			break
		}
	}

	// Nothing found...
	if unMatched {
		router.notFound(res, req)
	}
}

// Helper function to actually register the requestHandler on the router
func (router *Router) registerRequestHandler(method string, path string, handler http.HandlerFunc) {
	reqHandler := makeRequestHandler(path, handler)
	router.routes[method] = append(router.routes[method], reqHandler)
}

// Helper function to dispatch the correct NotFoundHanler.
func (router *Router) notFound(w http.ResponseWriter, req *http.Request) {
	if router.NotFoundHandler != nil {
		router.NotFoundHandler(w, req)
	} else {
		http.NotFound(w, req)
	}
}

// Exported helper funcs
// ---------------------------

// Access the request parameters for a given request
func Params(req *http.Request) (reqParams map[string]string, ok bool) {
	reqParams, ok = paramsStore[req]
	return
}

// Private helper funcs
// ---------------------------

// Some paths use tokens like "/user/:userid" where "userid" is the token.
//
// This function builds a string to be compiled as a regexp to match those
// paths and returns the names of the parameters found in the route.
func buildRegexpFor(path string) (regexpPath string, withParamNames []string) {
	parts := strings.Split(path, "/")
	items := make([]string, 0)
{'fraction_non_alphanumeric': 0.14220747295968536, 'fraction_numerical': 0.0012291052114060963, 'mean_word_length': 3.490618101545254, 'pattern_counts': {'":': 8, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6999817', 'n_tokens_mistral': 2416, 'n_tokens_neox': 2335, 'n_words': 864}