mirror of
https://github.com/kataras/iris.git
synced 2026-01-08 20:41:57 +00:00
Version 11 released. Read https://github.com/kataras/iris/blob/master/HISTORY.md#su-21-october-2018--v1100
Former-commit-id: fe6305deed00e170bf4d39a12c0644fe686e0a24
This commit is contained in:
@@ -7,9 +7,9 @@ import (
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/hero"
|
||||
"github.com/kataras/iris/hero/di"
|
||||
"github.com/kataras/iris/macro"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
)
|
||||
@@ -247,7 +247,7 @@ func (c *ControllerActivator) parseMethods() {
|
||||
}
|
||||
|
||||
func (c *ControllerActivator) parseMethod(m reflect.Method) {
|
||||
httpMethod, httpPath, err := parseMethod(m, c.isReservedMethod)
|
||||
httpMethod, httpPath, err := parseMethod(*c.router.Macros(), m, c.isReservedMethod)
|
||||
if err != nil {
|
||||
if err != errSkip {
|
||||
c.addErr(fmt.Errorf("MVC: fail to parse the route path and HTTP method for '%s.%s': %v", c.fullName, m.Name, err))
|
||||
@@ -283,7 +283,7 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
||||
}
|
||||
|
||||
// parse a route template which contains the parameters organised.
|
||||
tmpl, err := macro.Parse(path, c.router.Macros())
|
||||
tmpl, err := macro.Parse(path, *c.router.Macros())
|
||||
if err != nil {
|
||||
c.addErr(fmt.Errorf("MVC: fail to parse the path for '%s.%s': %v", c.fullName, funcName, err))
|
||||
return nil
|
||||
@@ -338,6 +338,7 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
|
||||
}
|
||||
|
||||
// fmt.Printf("for %s | values: %s\n", funcName, funcDependencies)
|
||||
|
||||
funcInjector := di.Func(m.Func, funcDependencies...)
|
||||
// fmt.Printf("actual injector's inputs length: %d\n", funcInjector.Length)
|
||||
if funcInjector.Has {
|
||||
@@ -396,6 +397,11 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
|
||||
in := make([]reflect.Value, n, n)
|
||||
in[0] = ctrl
|
||||
funcInjector.Inject(&in, ctxValue)
|
||||
|
||||
// for idxx, inn := range in {
|
||||
// println("controller.go: execution: in.Value = "+inn.String()+" and in.Type = "+inn.Type().Kind().String()+" of index: ", idxx)
|
||||
// }
|
||||
|
||||
hero.DispatchFuncResult(ctx, call(in))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type testControllerHandle struct {
|
||||
func (c *testControllerHandle) BeforeActivation(b BeforeActivation) {
|
||||
b.Handle("GET", "/histatic", "HiStatic")
|
||||
b.Handle("GET", "/hiservice", "HiService")
|
||||
b.Handle("GET", "/hiservice/{ps:string}", "HiServiceBy")
|
||||
b.Handle("GET", "/hiparam/{ps:string}", "HiParamBy")
|
||||
b.Handle("GET", "/hiparamempyinput/{ps:string}", "HiParamEmptyInputBy")
|
||||
}
|
||||
@@ -84,6 +85,10 @@ func (c *testControllerHandle) HiService() string {
|
||||
return c.Service.Say("hi")
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) HiServiceBy(v string) string {
|
||||
return c.Service.Say("hi with param: " + v)
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) HiParamBy(v string) string {
|
||||
return v
|
||||
}
|
||||
@@ -116,7 +121,8 @@ func TestControllerHandle(t *testing.T) {
|
||||
// and can be used in a user-defined, dynamic "mvc handler".
|
||||
e.GET("/hiservice").Expect().Status(httptest.StatusOK).
|
||||
Body().Equal("service: hi")
|
||||
|
||||
e.GET("/hiservice/value").Expect().Status(httptest.StatusOK).
|
||||
Body().Equal("service: hi with param: value")
|
||||
// this worked with a temporary variadic on the resolvemethodfunc which is not
|
||||
// correct design, I should split the path and params with the rest of implementation
|
||||
// in order a simple template.Src can be given.
|
||||
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -95,47 +96,25 @@ func (l *methodLexer) peekPrev() (w string) {
|
||||
return w
|
||||
}
|
||||
|
||||
var posWords = map[int]string{
|
||||
0: "",
|
||||
1: "first",
|
||||
2: "second",
|
||||
3: "third",
|
||||
4: "forth",
|
||||
5: "five",
|
||||
6: "sixth",
|
||||
7: "seventh",
|
||||
8: "eighth",
|
||||
9: "ninth",
|
||||
10: "tenth",
|
||||
11: "eleventh",
|
||||
12: "twelfth",
|
||||
13: "thirteenth",
|
||||
14: "fourteenth",
|
||||
15: "fifteenth",
|
||||
16: "sixteenth",
|
||||
17: "seventeenth",
|
||||
18: "eighteenth",
|
||||
19: "nineteenth",
|
||||
20: "twentieth",
|
||||
}
|
||||
|
||||
func genParamKey(argIdx int) string {
|
||||
return "arg" + posWords[argIdx] // argfirst, argsecond...
|
||||
return "param" + strconv.Itoa(argIdx) // param0, param1, param2...
|
||||
}
|
||||
|
||||
type methodParser struct {
|
||||
lexer *methodLexer
|
||||
fn reflect.Method
|
||||
lexer *methodLexer
|
||||
fn reflect.Method
|
||||
macros macro.Macros
|
||||
}
|
||||
|
||||
func parseMethod(fn reflect.Method, skipper func(string) bool) (method, path string, err error) {
|
||||
func parseMethod(macros macro.Macros, fn reflect.Method, skipper func(string) bool) (method, path string, err error) {
|
||||
if skipper(fn.Name) {
|
||||
return "", "", errSkip
|
||||
}
|
||||
|
||||
p := &methodParser{
|
||||
fn: fn,
|
||||
lexer: newMethodLexer(fn.Name),
|
||||
fn: fn,
|
||||
lexer: newMethodLexer(fn.Name),
|
||||
macros: macros,
|
||||
}
|
||||
return p.parse()
|
||||
}
|
||||
@@ -211,34 +190,45 @@ func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (st
|
||||
|
||||
var (
|
||||
paramKey = genParamKey(funcArgPos) // argfirst, argsecond...
|
||||
paramType = ast.ParamTypeString // default string
|
||||
m = p.macros.GetMaster() // default (String by-default)
|
||||
trailings = p.macros.GetTrailings()
|
||||
)
|
||||
|
||||
// string, int...
|
||||
goType := typ.In(funcArgPos).Name()
|
||||
goType := typ.In(funcArgPos).Kind()
|
||||
nextWord := p.lexer.peekNext()
|
||||
|
||||
if nextWord == tokenWildcard {
|
||||
p.lexer.skip() // skip the Wildcard word.
|
||||
paramType = ast.ParamTypePath
|
||||
} else if pType := ast.LookupParamTypeFromStd(goType); pType != ast.ParamTypeUnExpected {
|
||||
// it's not wildcard, so check base on our available macro types.
|
||||
paramType = pType
|
||||
} else {
|
||||
if typ.NumIn() > funcArgPos {
|
||||
// has more input arguments but we are not in the correct
|
||||
// index now, maybe the first argument was an `iris/context.Context`
|
||||
// so retry with the "funcArgPos" incremented.
|
||||
//
|
||||
// the "funcArgPos" will be updated to the caller as well
|
||||
// because we return it among the path and the error.
|
||||
return p.parsePathParam(path, w, funcArgPos+1)
|
||||
if len(trailings) == 0 {
|
||||
return "", 0, errors.New("no trailing path parameter found")
|
||||
}
|
||||
m = trailings[0]
|
||||
} else {
|
||||
// validMacros := p.macros.LookupForGoType(goType)
|
||||
|
||||
// instead of mapping with a reflect.Kind which has its limitation,
|
||||
// we map the param types with a go type as a string,
|
||||
// so custom structs such as "user" can be mapped to a macro with indent || alias == "user".
|
||||
m = p.macros.Get(strings.ToLower(goType.String()))
|
||||
|
||||
if m == nil {
|
||||
if typ.NumIn() > funcArgPos {
|
||||
// has more input arguments but we are not in the correct
|
||||
// index now, maybe the first argument was an `iris/context.Context`
|
||||
// so retry with the "funcArgPos" incremented.
|
||||
//
|
||||
// the "funcArgPos" will be updated to the caller as well
|
||||
// because we return it among the path and the error.
|
||||
return p.parsePathParam(path, w, funcArgPos+1)
|
||||
}
|
||||
|
||||
return "", 0, fmt.Errorf("invalid syntax: the standard go type: %s found in controller's function: %s at position: %d does not match any valid macro", goType, p.fn.Name, funcArgPos)
|
||||
}
|
||||
return "", 0, errors.New("invalid syntax for " + p.fn.Name)
|
||||
}
|
||||
|
||||
// /{argfirst:path}, /{argfirst:long}...
|
||||
path += fmt.Sprintf("/{%s:%s}", paramKey, paramType.String())
|
||||
path += fmt.Sprintf("/{%s:%s}", paramKey, m.Indent())
|
||||
|
||||
if nextWord == "" && typ.NumIn() > funcArgPos+1 {
|
||||
// By is the latest word but func is expected
|
||||
|
||||
@@ -365,7 +365,9 @@ func (c *testControllerRelPathFromFunc) EndRequest(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) Get() {}
|
||||
func (c *testControllerRelPathFromFunc) GetBy(int64) {}
|
||||
func (c *testControllerRelPathFromFunc) GetBy(uint64) {}
|
||||
func (c *testControllerRelPathFromFunc) GetUint8RatioBy(uint8) {}
|
||||
func (c *testControllerRelPathFromFunc) GetInt64RatioBy(int64) {}
|
||||
func (c *testControllerRelPathFromFunc) GetAnythingByWildcard(string) {}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) GetLogin() {}
|
||||
@@ -375,8 +377,10 @@ func (c *testControllerRelPathFromFunc) GetAdminLogin() {}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) PutSomethingIntoThis() {}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingBy(bool) {}
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingByBy(string, int) {}
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingBy(bool) {}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingByBy(string, int) {}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingNewBy(string, int) {} // two input arguments, one By which is the latest word.
|
||||
func (c *testControllerRelPathFromFunc) GetSomethingByElseThisBy(bool, int) {} // two input arguments
|
||||
|
||||
@@ -388,8 +392,13 @@ func TestControllerRelPathFromFunc(t *testing.T) {
|
||||
e.GET("/").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/")
|
||||
|
||||
e.GET("/42").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/42")
|
||||
e.GET("/18446744073709551615").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/18446744073709551615")
|
||||
e.GET("/uint8/ratio/255").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/uint8/ratio/255")
|
||||
e.GET("/uint8/ratio/256").Expect().Status(iris.StatusNotFound)
|
||||
e.GET("/int64/ratio/-42").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/int64/ratio/-42")
|
||||
e.GET("/something/true").Expect().Status(iris.StatusOK).
|
||||
Body().Equal("GET:/something/true")
|
||||
e.GET("/something/false").Expect().Status(iris.StatusOK).
|
||||
|
||||
78
mvc/param.go
78
mvc/param.go
@@ -4,8 +4,7 @@ import (
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type) (values []reflect.Value) {
|
||||
@@ -13,51 +12,40 @@ func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type)
|
||||
return
|
||||
}
|
||||
|
||||
consumedParams := make(map[int]bool, 0)
|
||||
for _, in := range funcIn {
|
||||
for j, p := range params {
|
||||
if _, consumed := consumedParams[j]; consumed {
|
||||
continue
|
||||
}
|
||||
paramType := p.Type
|
||||
paramName := p.Name
|
||||
// fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
|
||||
if paramType.Assignable(in.Kind()) {
|
||||
consumedParams[j] = true
|
||||
// fmt.Printf("param.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
|
||||
values = append(values, makeFuncParamGetter(paramType, paramName))
|
||||
}
|
||||
// consumedParams := make(map[int]bool, 0)
|
||||
// for _, in := range funcIn {
|
||||
// for j, p := range params {
|
||||
// if _, consumed := consumedParams[j]; consumed {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// // fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
|
||||
// if m := macros.Lookup(p.Type); m != nil && m.GoType == in.Kind() {
|
||||
// consumedParams[j] = true
|
||||
// // fmt.Printf("param.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
|
||||
// funcDep, ok := context.ParamResolverByKindAndIndex(m.GoType, p.Index)
|
||||
// // funcDep, ok := context.ParamResolverByKindAndKey(in.Kind(), paramName)
|
||||
// if !ok {
|
||||
// // here we can add a logger about invalid parameter type although it should never happen here
|
||||
// // unless the end-developer modified the macro/macros with a special type but not the context/ParamResolvers.
|
||||
// continue
|
||||
// }
|
||||
// values = append(values, funcDep)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
for i, param := range params {
|
||||
if len(funcIn) <= i {
|
||||
return
|
||||
}
|
||||
funcDep, ok := context.ParamResolverByTypeAndIndex(funcIn[i], param.Index)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
values = append(values, funcDep)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func makeFuncParamGetter(paramType ast.ParamType, paramName string) reflect.Value {
|
||||
var fn interface{}
|
||||
|
||||
switch paramType {
|
||||
case ast.ParamTypeInt:
|
||||
fn = func(ctx context.Context) int {
|
||||
v, _ := ctx.Params().GetInt(paramName)
|
||||
return v
|
||||
}
|
||||
case ast.ParamTypeLong:
|
||||
fn = func(ctx context.Context) int64 {
|
||||
v, _ := ctx.Params().GetInt64(paramName)
|
||||
return v
|
||||
}
|
||||
case ast.ParamTypeBoolean:
|
||||
fn = func(ctx context.Context) bool {
|
||||
v, _ := ctx.Params().GetBool(paramName)
|
||||
return v
|
||||
}
|
||||
default:
|
||||
// string, path...
|
||||
fn = func(ctx context.Context) string {
|
||||
return ctx.Params().Get(paramName)
|
||||
}
|
||||
}
|
||||
|
||||
return reflect.ValueOf(fn)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user