diff --git a/_examples/routing/macros/main.go b/_examples/routing/macros/main.go index fe68c598..9361ff5f 100644 --- a/_examples/routing/macros/main.go +++ b/_examples/routing/macros/main.go @@ -72,7 +72,7 @@ func main() { ) ctx.Writef("myparam1: %s | myparam2: %s", myparam1, myparam2) - }) + }, func(ctx context.Context) {}) app.Get("/test_string2/{myparam1}/{myparam2}", func(ctx context.Context) { var ( diff --git a/core/router/path.go b/core/router/path.go index 05ba11c3..11d4ffd0 100644 --- a/core/router/path.go +++ b/core/router/path.go @@ -33,7 +33,7 @@ func WildcardParam(name string) string { return prefix(name, WildcardParamStart) } -func convertMacroTmplToNodePath(tmpl *macro.Template) string { +func convertMacroTmplToNodePath(tmpl macro.Template) string { routePath := tmpl.Src if len(tmpl.Params) > 0 { if routePath[len(routePath)-1] == '/' { diff --git a/core/router/route.go b/core/router/route.go index 5e0e6ef0..132eb7c7 100644 --- a/core/router/route.go +++ b/core/router/route.go @@ -13,11 +13,11 @@ import ( // If any of the following fields are changed then the // caller should Refresh the router. type Route struct { - Name string `json:"name"` // "userRoute" - Method string `json:"method"` // "GET" - methodBckp string // if Method changed to something else (which is possible at runtime as well, via RefreshRouter) then this field will be filled with the old one. - Subdomain string `json:"subdomain"` // "admin." - tmpl *macro.Template // Tmpl().Src: "/api/user/{id:uint64}" + Name string `json:"name"` // "userRoute" + Method string `json:"method"` // "GET" + methodBckp string // if Method changed to something else (which is possible at runtime as well, via RefreshRouter) then this field will be filled with the old one. + Subdomain string `json:"subdomain"` // "admin." + tmpl macro.Template // Tmpl().Src: "/api/user/{id:uint64}" // temp storage, they're appended to the Handlers on build. // Execution happens before Handlers, can be empty. beginHandlers context.Handlers @@ -50,7 +50,8 @@ func NewRoute(method, subdomain, unparsedPath, mainHandlerName string, path := convertMacroTmplToNodePath(tmpl) // prepend the macro handler to the route, now, // right before the register to the tree, so APIBuilder#UseGlobal will work as expected. - if macroEvaluatorHandler, ok := handler.MakeHandler(tmpl); ok { + if handler.CanMakeHandler(tmpl) { + macroEvaluatorHandler := handler.MakeHandler(tmpl) handlers = append(context.Handlers{macroEvaluatorHandler}, handlers...) } @@ -155,7 +156,18 @@ func (r Route) String() string { // via Tmpl().Src, Route.Path is the path // converted to match the underline router's specs. func (r Route) Tmpl() macro.Template { - return *r.tmpl + return r.tmpl +} + +// RegisteredHandlersLen returns the end-developer's registered handlers, all except the macro evaluator handler +// if was required by the build process. +func (r Route) RegisteredHandlersLen() int { + n := len(r.Handlers) + if handler.CanMakeHandler(r.tmpl) { + n-- + } + + return n } // IsOnline returns true if the route is marked as "online" (state). @@ -245,7 +257,8 @@ func (r Route) Trace() string { printfmt += fmt.Sprintf(" %s", r.Subdomain) } printfmt += fmt.Sprintf(" %s ", r.Tmpl().Src) - if l := len(r.Handlers); l > 1 { + + if l := r.RegisteredHandlersLen(); l > 1 { printfmt += fmt.Sprintf("-> %s() and %d more", r.MainHandlerName, l-1) } else { printfmt += fmt.Sprintf("-> %s()", r.MainHandlerName) diff --git a/macro/handler/handler.go b/macro/handler/handler.go index e3f10859..16f466c1 100644 --- a/macro/handler/handler.go +++ b/macro/handler/handler.go @@ -7,11 +7,11 @@ import ( "github.com/kataras/iris/macro" ) -// MakeHandler creates and returns a handler from a macro template, the handler evaluates each of the parameters if necessary at all. +// CanMakeHandler reports whether a macro template needs a special macro's evaluator handler to be validated +// before procceed to the next handler(s). // If the template does not contain any dynamic attributes and a special handler is NOT required -// then it returns a nil handler and false as its second output value, -// the caller should check those two values before any further action. -func MakeHandler(tmpl *macro.Template) (handler context.Handler, needsMacroHandler bool) { +// then it returns false. +func CanMakeHandler(tmpl macro.Template) (needsMacroHandler bool) { if len(tmpl.Params) == 0 { return } @@ -27,11 +27,18 @@ func MakeHandler(tmpl *macro.Template) (handler context.Handler, needsMacroHandl } } - if !needsMacroHandler { - return + return +} + +// MakeHandler creates and returns a handler from a macro template, the handler evaluates each of the parameters if necessary at all. +// If the template does not contain any dynamic attributes and a special handler is NOT required +// then it returns a nil handler. +func MakeHandler(tmpl macro.Template) context.Handler { + if !CanMakeHandler(tmpl) { + return nil } - handler = func(ctx context.Context) { + return func(ctx context.Context) { for _, p := range tmpl.Params { if !p.CanEval() { continue // allow. @@ -46,6 +53,4 @@ func MakeHandler(tmpl *macro.Template) (handler context.Handler, needsMacroHandl // if all passed, just continue. ctx.Next() } - - return } diff --git a/macro/handler/handler_test.go b/macro/handler/handler_test.go index c22ed663..0acc1e83 100644 --- a/macro/handler/handler_test.go +++ b/macro/handler/handler_test.go @@ -6,7 +6,7 @@ import ( "github.com/kataras/iris/macro" ) -func TestMakeHandlerNeeds(t *testing.T) { +func TestCanMakeHandler(t *testing.T) { tests := []struct { src string needsHandler bool @@ -29,13 +29,13 @@ func TestMakeHandlerNeeds(t *testing.T) { if err != nil { t.Fatalf("[%d] '%s' failed to be parsed: %v", i, tt.src, err) } - if _, got := MakeHandler(tmpl); got != tt.needsHandler { + + if got := CanMakeHandler(tmpl); got != tt.needsHandler { if tt.needsHandler { t.Fatalf("[%d] '%s' expected to be able to generate an evaluator handler instead of a nil one", i, tt.src) } else { t.Fatalf("[%d] '%s' should not need an evaluator handler", i, tt.src) } - } } } diff --git a/macro/template.go b/macro/template.go index 33b14734..cd83d9c7 100644 --- a/macro/template.go +++ b/macro/template.go @@ -95,18 +95,17 @@ func (p *TemplateParam) Eval(paramValue string, paramChanger memstore.ValueSette // and returns a new Template. // It builds all the parameter functions for that template // and their evaluators, it's the api call that makes use the interpeter's parser -> lexer. -func Parse(src string, macros Macros) (*Template, error) { +func Parse(src string, macros Macros) (Template, error) { types := make([]ast.ParamType, len(macros)) for i, m := range macros { types[i] = m } + tmpl := Template{Src: src} params, err := parser.Parse(src, types) if err != nil { - return nil, err + return tmpl, err } - t := new(Template) - t.Src = src for idx, p := range params { m := macros.Lookup(p.Type) @@ -140,8 +139,8 @@ func Parse(src string, macros Macros) (*Template, error) { tmplParam.Funcs = append(tmplParam.Funcs, evalFn) } - t.Params = append(t.Params, tmplParam.preComputed()) + tmpl.Params = append(tmpl.Params, tmplParam.preComputed()) } - return t, nil + return tmpl, nil }